From 96ea91717d3ee81bdc5f4e3822e5872f615cf6e2 Mon Sep 17 00:00:00 2001 From: Sagittaeri Date: Sun, 22 Jan 2017 05:02:08 +1100 Subject: [PATCH] pretty dof on pause and gameover screen, also boulder catapults --- .../Assets/Art/Models/lightHouse_LOW.obj.meta | 82 - .../Assets/Scripts/AlertController.cs | 8 +- .../Assets/Scripts/Boulder.cs | 16 + .../Assets/Scripts/Boulder.cs.meta | 12 + .../Assets/Scripts/Catapult.cs | 85 + .../Assets/Scripts/Catapult.cs.meta | 12 + .../Assets/Scripts/Lighthouse.cs | 2 +- .../Assets/Scripts/ScreenEffects.cs | 52 + .../Assets/Scripts/ScreenEffects.cs.meta | 12 + .../Assets/Scripts/Searchlight.cs | 7 +- .../Assets/Scripts/UIPanel.cs | 6 +- IronToad_UnityProject/Assets/Sound.meta | 9 + .../Effects/AmbientOcclusion.meta | 9 + .../AmbientOcclusion/AmbientOcclusion.cs | 360 +++ .../AmbientOcclusion/AmbientOcclusion.cs.meta | 14 + .../Effects/AmbientOcclusion/Editor.meta | 9 + .../Editor/AmbientOcclusionEditor.cs | 89 + .../Editor/AmbientOcclusionEditor.cs.meta | 12 + .../Effects/AmbientOcclusion/Helpers.meta | 9 + .../Helpers/PropertyObserver.cs | 44 + .../Helpers/PropertyObserver.cs.meta | 12 + .../AmbientOcclusion/Helpers/Settings.cs | 85 + .../AmbientOcclusion/Helpers/Settings.cs.meta | 12 + .../Effects/AmbientOcclusion/Resources.meta | 9 + .../Resources/AmbientOcclusion.cginc | 409 ++++ .../Resources/AmbientOcclusion.cginc.meta | 9 + .../Resources/AmbientOcclusion.shader | 129 ++ .../Resources/AmbientOcclusion.shader.meta | 9 + .../Standard Assets/Effects/AntiAliasing.meta | 9 + .../Effects/AntiAliasing/AntiAliasing.cs | 90 + .../Effects/AntiAliasing/AntiAliasing.cs.meta | 12 + .../Effects/AntiAliasing/Editor.meta | 9 + .../AntiAliasing/Editor/AntiAliasingEditor.cs | 64 + .../Editor/AntiAliasingEditor.cs.meta | 12 + .../Editor/IAntiAliasingEditor.cs | 10 + .../Editor/IAntiAliasingEditor.cs.meta | 12 + .../Effects/AntiAliasing/FXAA.meta | 9 + .../Effects/AntiAliasing/FXAA/Editor.meta | 9 + .../AntiAliasing/FXAA/Editor/FXAAEditor.cs | 57 + .../FXAA/Editor/FXAAEditor.cs.meta | 12 + .../Effects/AntiAliasing/FXAA/FXAA.cs | 255 ++ .../Effects/AntiAliasing/FXAA/FXAA.cs.meta | 13 + .../Effects/AntiAliasing/FXAA/Resources.meta | 9 + .../AntiAliasing/FXAA/Resources/FXAA.shader | 104 + .../FXAA/Resources/FXAA.shader.meta | 9 + .../AntiAliasing/FXAA/Resources/FXAA3.cginc | 2047 +++++++++++++++++ .../FXAA/Resources/FXAA3.cginc.meta | 9 + .../Effects/AntiAliasing/IAntiAliasing.cs | 13 + .../AntiAliasing/IAntiAliasing.cs.meta | 12 + .../Effects/AntiAliasing/SMAA.meta | 9 + .../Effects/AntiAliasing/SMAA/Editor.meta | 9 + .../AntiAliasing/SMAA/Editor/SMAAEditor.cs | 106 + .../SMAA/Editor/SMAAEditor.cs.meta | 12 + .../Effects/AntiAliasing/SMAA/Resources.meta | 9 + .../AntiAliasing/SMAA/Resources/AreaTex.tga | Bin 0 -> 358444 bytes .../SMAA/Resources/AreaTex.tga.meta | 57 + .../AntiAliasing/SMAA/Resources/SMAA.cginc | 1433 ++++++++++++ .../SMAA/Resources/SMAA.cginc.meta | 9 + .../AntiAliasing/SMAA/Resources/SMAA.shader | 382 +++ .../SMAA/Resources/SMAA.shader.meta | 9 + .../AntiAliasing/SMAA/Resources/SearchTex.tga | Bin 0 -> 3116 bytes .../SMAA/Resources/SearchTex.tga.meta | 57 + .../Effects/AntiAliasing/SMAA/SMAA.cs | 484 ++++ .../Effects/AntiAliasing/SMAA/SMAA.cs.meta | 13 + .../Assets/Standard Assets/Effects/Bloom.meta | 9 + .../Standard Assets/Effects/Bloom/Bloom.cs | 205 ++ .../Effects/Bloom/Bloom.cs.meta | 13 + .../Standard Assets/Effects/Bloom/Editor.meta | 9 + .../Effects/Bloom/Editor/BloomEditor.cs | 54 + .../Effects/Bloom/Editor/BloomEditor.cs.meta | 12 + .../Effects/Bloom/Editor/BloomGraphDrawer.cs | 156 ++ .../Bloom/Editor/BloomGraphDrawer.cs.meta | 12 + .../Effects/Bloom/Resources.meta | 9 + .../Effects/Bloom/Resources/Bloom.cginc | 238 ++ .../Effects/Bloom/Resources/Bloom.cginc.meta | 9 + .../Effects/Bloom/Resources/Bloom.shader | 118 + .../Effects/Bloom/Resources/Bloom.shader.meta | 9 + .../Standard Assets/Effects/Common.meta | 9 + .../Effects/Common/Editor.meta | 9 + .../Effects/Common/Editor/EditorGUIHelper.cs | 62 + .../Common/Editor/EditorGUIHelper.cs.meta | 12 + .../Effects/Common/Editor/FieldFinder.cs | 25 + .../Effects/Common/Editor/FieldFinder.cs.meta | 12 + .../Effects/Common/Editor/MinDrawer.cs | 29 + .../Effects/Common/Editor/MinDrawer.cs.meta | 12 + .../Effects/Common/ImageEffectHelper.cs | 63 + .../Effects/Common/ImageEffectHelper.cs.meta | 12 + .../Effects/Common/MinAttribute.cs | 14 + .../Effects/Common/MinAttribute.cs.meta | 12 + .../Effects/Common/RenderTextureUtility.cs | 44 + .../Common/RenderTextureUtility.cs.meta | 12 + .../Standard Assets/Effects/DepthOfField.meta | 9 + .../Effects/DepthOfField/DepthOfField.cs | 846 +++++++ .../Effects/DepthOfField/DepthOfField.cs.meta | 18 + .../Effects/DepthOfField/Editor.meta | 9 + .../DepthOfField/Editor/DepthOfFieldEditor.cs | 139 ++ .../Editor/DepthOfFieldEditor.cs.meta | 12 + .../Effects/DepthOfField/Helpers.meta | 9 + .../Effects/DepthOfField/Helpers/HexShape.psd | Bin 0 -> 478144 bytes .../DepthOfField/Helpers/HexShape.psd.meta | 55 + .../DepthOfField/Helpers/RoundedHexShape.tif | Bin 0 -> 32876 bytes .../Helpers/RoundedHexShape.tif.meta | 57 + .../DepthOfField/Helpers/SphereShape.psd | Bin 0 -> 492716 bytes .../DepthOfField/Helpers/SphereShape.psd.meta | 55 + .../Effects/DepthOfField/Resources.meta | 9 + .../Resources/BokehSplatting.shader | 235 ++ .../Resources/BokehSplatting.shader.meta | 9 + .../Resources/DepthOfField.shader | 1221 ++++++++++ .../Resources/DepthOfField.shader.meta | 9 + .../Resources/MedianFilter.shader | 162 ++ .../Resources/MedianFilter.shader.meta | 9 + .../Effects/LensAberrations.meta | 9 + .../Effects/LensAberrations/Editor.meta | 9 + .../Editor/LensAberrationsEditor.cs | 81 + .../Editor/LensAberrationsEditor.cs.meta | 12 + .../LensAberrations/LensAberrations.cs | 311 +++ .../LensAberrations/LensAberrations.cs.meta | 13 + .../Effects/LensAberrations/Resources.meta | 9 + .../Resources/LensAberrations.shader | 293 +++ .../Resources/LensAberrations.shader.meta | 9 + .../Effects/ScreenSpaceReflection.meta | 9 + .../Effects/ScreenSpaceReflection/Editor.meta | 9 + .../Editor/ScreenSpaceReflectionEditor.cs | 117 + .../ScreenSpaceReflectionEditor.cs.meta | 12 + .../ScreenSpaceReflection/Resources.meta | 9 + .../Resources/ScreenSpaceRaytrace.cginc | 243 ++ .../Resources/ScreenSpaceRaytrace.cginc.meta | 9 + .../Resources/ScreenSpaceReflection.shader | 949 ++++++++ .../ScreenSpaceReflection.shader.meta | 9 + .../ScreenSpaceReflection.cs | 424 ++++ .../ScreenSpaceReflection.cs.meta | 13 + .../Effects/TonemappingColorGrading.meta | 9 + .../TonemappingColorGrading/Editor.meta | 9 + .../Editor/TonemappingColorGradingEditor.cs | 736 ++++++ .../TonemappingColorGradingEditor.cs.meta | 12 + .../TonemappingColorGrading/Helpers.meta | 9 + .../Helpers/NeutralLUT16.png | Bin 0 -> 982 bytes .../Helpers/NeutralLUT16.png.meta | 57 + .../Helpers/NeutralLUT32.png | Bin 0 -> 1165 bytes .../Helpers/NeutralLUT32.png.meta | 57 + .../TonemappingColorGrading/Resources.meta | 9 + .../Resources/HistogramCompute.compute | 85 + .../Resources/HistogramCompute.compute.meta | 9 + .../Resources/HistogramRender.shader | 104 + .../Resources/HistogramRender.shader.meta | 9 + .../Resources/TonemappingColorGrading.cginc | 260 +++ .../TonemappingColorGrading.cginc.meta | 9 + .../Resources/TonemappingColorGrading.shader | 305 +++ .../TonemappingColorGrading.shader.meta | 9 + .../TonemappingColorGrading.cs | 1044 +++++++++ .../TonemappingColorGrading.cs.meta | 16 + .../Assets/_Scenes/LighthouseTestScene.unity | Bin 105584 -> 114152 bytes 152 files changed, 16135 insertions(+), 93 deletions(-) delete mode 100644 IronToad_UnityProject/Assets/Art/Models/lightHouse_LOW.obj.meta create mode 100644 IronToad_UnityProject/Assets/Scripts/Boulder.cs create mode 100644 IronToad_UnityProject/Assets/Scripts/Boulder.cs.meta create mode 100644 IronToad_UnityProject/Assets/Scripts/Catapult.cs create mode 100644 IronToad_UnityProject/Assets/Scripts/Catapult.cs.meta create mode 100644 IronToad_UnityProject/Assets/Scripts/ScreenEffects.cs create mode 100644 IronToad_UnityProject/Assets/Scripts/ScreenEffects.cs.meta create mode 100644 IronToad_UnityProject/Assets/Sound.meta create mode 100644 IronToad_UnityProject/Assets/Standard Assets/Effects/AmbientOcclusion.meta create mode 100644 IronToad_UnityProject/Assets/Standard Assets/Effects/AmbientOcclusion/AmbientOcclusion.cs create mode 100644 IronToad_UnityProject/Assets/Standard Assets/Effects/AmbientOcclusion/AmbientOcclusion.cs.meta create mode 100644 IronToad_UnityProject/Assets/Standard Assets/Effects/AmbientOcclusion/Editor.meta create mode 100644 IronToad_UnityProject/Assets/Standard Assets/Effects/AmbientOcclusion/Editor/AmbientOcclusionEditor.cs create mode 100644 IronToad_UnityProject/Assets/Standard Assets/Effects/AmbientOcclusion/Editor/AmbientOcclusionEditor.cs.meta create mode 100644 IronToad_UnityProject/Assets/Standard Assets/Effects/AmbientOcclusion/Helpers.meta create mode 100644 IronToad_UnityProject/Assets/Standard Assets/Effects/AmbientOcclusion/Helpers/PropertyObserver.cs create mode 100644 IronToad_UnityProject/Assets/Standard Assets/Effects/AmbientOcclusion/Helpers/PropertyObserver.cs.meta create mode 100644 IronToad_UnityProject/Assets/Standard Assets/Effects/AmbientOcclusion/Helpers/Settings.cs create mode 100644 IronToad_UnityProject/Assets/Standard Assets/Effects/AmbientOcclusion/Helpers/Settings.cs.meta create mode 100644 IronToad_UnityProject/Assets/Standard Assets/Effects/AmbientOcclusion/Resources.meta create mode 100644 IronToad_UnityProject/Assets/Standard Assets/Effects/AmbientOcclusion/Resources/AmbientOcclusion.cginc create mode 100644 IronToad_UnityProject/Assets/Standard Assets/Effects/AmbientOcclusion/Resources/AmbientOcclusion.cginc.meta create mode 100644 IronToad_UnityProject/Assets/Standard Assets/Effects/AmbientOcclusion/Resources/AmbientOcclusion.shader create mode 100644 IronToad_UnityProject/Assets/Standard Assets/Effects/AmbientOcclusion/Resources/AmbientOcclusion.shader.meta create mode 100644 IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing.meta create mode 100644 IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/AntiAliasing.cs create mode 100644 IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/AntiAliasing.cs.meta create mode 100644 IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/Editor.meta create mode 100644 IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/Editor/AntiAliasingEditor.cs create mode 100644 IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/Editor/AntiAliasingEditor.cs.meta create mode 100644 IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/Editor/IAntiAliasingEditor.cs create mode 100644 IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/Editor/IAntiAliasingEditor.cs.meta create mode 100644 IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/FXAA.meta create mode 100644 IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/FXAA/Editor.meta create mode 100644 IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/FXAA/Editor/FXAAEditor.cs create mode 100644 IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/FXAA/Editor/FXAAEditor.cs.meta create mode 100644 IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/FXAA/FXAA.cs create mode 100644 IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/FXAA/FXAA.cs.meta create mode 100644 IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/FXAA/Resources.meta create mode 100644 IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/FXAA/Resources/FXAA.shader create mode 100644 IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/FXAA/Resources/FXAA.shader.meta create mode 100644 IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/FXAA/Resources/FXAA3.cginc create mode 100644 IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/FXAA/Resources/FXAA3.cginc.meta create mode 100644 IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/IAntiAliasing.cs create mode 100644 IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/IAntiAliasing.cs.meta create mode 100644 IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/SMAA.meta create mode 100644 IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/SMAA/Editor.meta create mode 100644 IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/SMAA/Editor/SMAAEditor.cs create mode 100644 IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/SMAA/Editor/SMAAEditor.cs.meta create mode 100644 IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/SMAA/Resources.meta create mode 100644 IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/SMAA/Resources/AreaTex.tga create mode 100644 IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/SMAA/Resources/AreaTex.tga.meta create mode 100644 IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/SMAA/Resources/SMAA.cginc create mode 100644 IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/SMAA/Resources/SMAA.cginc.meta create mode 100644 IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/SMAA/Resources/SMAA.shader create mode 100644 IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/SMAA/Resources/SMAA.shader.meta create mode 100644 IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/SMAA/Resources/SearchTex.tga create mode 100644 IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/SMAA/Resources/SearchTex.tga.meta create mode 100644 IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/SMAA/SMAA.cs create mode 100644 IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/SMAA/SMAA.cs.meta create mode 100644 IronToad_UnityProject/Assets/Standard Assets/Effects/Bloom.meta create mode 100644 IronToad_UnityProject/Assets/Standard Assets/Effects/Bloom/Bloom.cs create mode 100644 IronToad_UnityProject/Assets/Standard Assets/Effects/Bloom/Bloom.cs.meta create mode 100644 IronToad_UnityProject/Assets/Standard Assets/Effects/Bloom/Editor.meta create mode 100644 IronToad_UnityProject/Assets/Standard Assets/Effects/Bloom/Editor/BloomEditor.cs create mode 100644 IronToad_UnityProject/Assets/Standard Assets/Effects/Bloom/Editor/BloomEditor.cs.meta create mode 100644 IronToad_UnityProject/Assets/Standard Assets/Effects/Bloom/Editor/BloomGraphDrawer.cs create mode 100644 IronToad_UnityProject/Assets/Standard Assets/Effects/Bloom/Editor/BloomGraphDrawer.cs.meta create mode 100644 IronToad_UnityProject/Assets/Standard Assets/Effects/Bloom/Resources.meta create mode 100644 IronToad_UnityProject/Assets/Standard Assets/Effects/Bloom/Resources/Bloom.cginc create mode 100644 IronToad_UnityProject/Assets/Standard Assets/Effects/Bloom/Resources/Bloom.cginc.meta create mode 100644 IronToad_UnityProject/Assets/Standard Assets/Effects/Bloom/Resources/Bloom.shader create mode 100644 IronToad_UnityProject/Assets/Standard Assets/Effects/Bloom/Resources/Bloom.shader.meta create mode 100644 IronToad_UnityProject/Assets/Standard Assets/Effects/Common.meta create mode 100644 IronToad_UnityProject/Assets/Standard Assets/Effects/Common/Editor.meta create mode 100644 IronToad_UnityProject/Assets/Standard Assets/Effects/Common/Editor/EditorGUIHelper.cs create mode 100644 IronToad_UnityProject/Assets/Standard Assets/Effects/Common/Editor/EditorGUIHelper.cs.meta create mode 100644 IronToad_UnityProject/Assets/Standard Assets/Effects/Common/Editor/FieldFinder.cs create mode 100644 IronToad_UnityProject/Assets/Standard Assets/Effects/Common/Editor/FieldFinder.cs.meta create mode 100644 IronToad_UnityProject/Assets/Standard Assets/Effects/Common/Editor/MinDrawer.cs create mode 100644 IronToad_UnityProject/Assets/Standard Assets/Effects/Common/Editor/MinDrawer.cs.meta create mode 100644 IronToad_UnityProject/Assets/Standard Assets/Effects/Common/ImageEffectHelper.cs create mode 100644 IronToad_UnityProject/Assets/Standard Assets/Effects/Common/ImageEffectHelper.cs.meta create mode 100644 IronToad_UnityProject/Assets/Standard Assets/Effects/Common/MinAttribute.cs create mode 100644 IronToad_UnityProject/Assets/Standard Assets/Effects/Common/MinAttribute.cs.meta create mode 100644 IronToad_UnityProject/Assets/Standard Assets/Effects/Common/RenderTextureUtility.cs create mode 100644 IronToad_UnityProject/Assets/Standard Assets/Effects/Common/RenderTextureUtility.cs.meta create mode 100644 IronToad_UnityProject/Assets/Standard Assets/Effects/DepthOfField.meta create mode 100644 IronToad_UnityProject/Assets/Standard Assets/Effects/DepthOfField/DepthOfField.cs create mode 100644 IronToad_UnityProject/Assets/Standard Assets/Effects/DepthOfField/DepthOfField.cs.meta create mode 100644 IronToad_UnityProject/Assets/Standard Assets/Effects/DepthOfField/Editor.meta create mode 100644 IronToad_UnityProject/Assets/Standard Assets/Effects/DepthOfField/Editor/DepthOfFieldEditor.cs create mode 100644 IronToad_UnityProject/Assets/Standard Assets/Effects/DepthOfField/Editor/DepthOfFieldEditor.cs.meta create mode 100644 IronToad_UnityProject/Assets/Standard Assets/Effects/DepthOfField/Helpers.meta create mode 100644 IronToad_UnityProject/Assets/Standard Assets/Effects/DepthOfField/Helpers/HexShape.psd create mode 100644 IronToad_UnityProject/Assets/Standard Assets/Effects/DepthOfField/Helpers/HexShape.psd.meta create mode 100644 IronToad_UnityProject/Assets/Standard Assets/Effects/DepthOfField/Helpers/RoundedHexShape.tif create mode 100644 IronToad_UnityProject/Assets/Standard Assets/Effects/DepthOfField/Helpers/RoundedHexShape.tif.meta create mode 100644 IronToad_UnityProject/Assets/Standard Assets/Effects/DepthOfField/Helpers/SphereShape.psd create mode 100644 IronToad_UnityProject/Assets/Standard Assets/Effects/DepthOfField/Helpers/SphereShape.psd.meta create mode 100644 IronToad_UnityProject/Assets/Standard Assets/Effects/DepthOfField/Resources.meta create mode 100644 IronToad_UnityProject/Assets/Standard Assets/Effects/DepthOfField/Resources/BokehSplatting.shader create mode 100644 IronToad_UnityProject/Assets/Standard Assets/Effects/DepthOfField/Resources/BokehSplatting.shader.meta create mode 100644 IronToad_UnityProject/Assets/Standard Assets/Effects/DepthOfField/Resources/DepthOfField.shader create mode 100644 IronToad_UnityProject/Assets/Standard Assets/Effects/DepthOfField/Resources/DepthOfField.shader.meta create mode 100644 IronToad_UnityProject/Assets/Standard Assets/Effects/DepthOfField/Resources/MedianFilter.shader create mode 100644 IronToad_UnityProject/Assets/Standard Assets/Effects/DepthOfField/Resources/MedianFilter.shader.meta create mode 100644 IronToad_UnityProject/Assets/Standard Assets/Effects/LensAberrations.meta create mode 100644 IronToad_UnityProject/Assets/Standard Assets/Effects/LensAberrations/Editor.meta create mode 100644 IronToad_UnityProject/Assets/Standard Assets/Effects/LensAberrations/Editor/LensAberrationsEditor.cs create mode 100644 IronToad_UnityProject/Assets/Standard Assets/Effects/LensAberrations/Editor/LensAberrationsEditor.cs.meta create mode 100644 IronToad_UnityProject/Assets/Standard Assets/Effects/LensAberrations/LensAberrations.cs create mode 100644 IronToad_UnityProject/Assets/Standard Assets/Effects/LensAberrations/LensAberrations.cs.meta create mode 100644 IronToad_UnityProject/Assets/Standard Assets/Effects/LensAberrations/Resources.meta create mode 100644 IronToad_UnityProject/Assets/Standard Assets/Effects/LensAberrations/Resources/LensAberrations.shader create mode 100644 IronToad_UnityProject/Assets/Standard Assets/Effects/LensAberrations/Resources/LensAberrations.shader.meta create mode 100644 IronToad_UnityProject/Assets/Standard Assets/Effects/ScreenSpaceReflection.meta create mode 100644 IronToad_UnityProject/Assets/Standard Assets/Effects/ScreenSpaceReflection/Editor.meta create mode 100644 IronToad_UnityProject/Assets/Standard Assets/Effects/ScreenSpaceReflection/Editor/ScreenSpaceReflectionEditor.cs create mode 100644 IronToad_UnityProject/Assets/Standard Assets/Effects/ScreenSpaceReflection/Editor/ScreenSpaceReflectionEditor.cs.meta create mode 100644 IronToad_UnityProject/Assets/Standard Assets/Effects/ScreenSpaceReflection/Resources.meta create mode 100644 IronToad_UnityProject/Assets/Standard Assets/Effects/ScreenSpaceReflection/Resources/ScreenSpaceRaytrace.cginc create mode 100644 IronToad_UnityProject/Assets/Standard Assets/Effects/ScreenSpaceReflection/Resources/ScreenSpaceRaytrace.cginc.meta create mode 100644 IronToad_UnityProject/Assets/Standard Assets/Effects/ScreenSpaceReflection/Resources/ScreenSpaceReflection.shader create mode 100644 IronToad_UnityProject/Assets/Standard Assets/Effects/ScreenSpaceReflection/Resources/ScreenSpaceReflection.shader.meta create mode 100644 IronToad_UnityProject/Assets/Standard Assets/Effects/ScreenSpaceReflection/ScreenSpaceReflection.cs create mode 100644 IronToad_UnityProject/Assets/Standard Assets/Effects/ScreenSpaceReflection/ScreenSpaceReflection.cs.meta create mode 100644 IronToad_UnityProject/Assets/Standard Assets/Effects/TonemappingColorGrading.meta create mode 100644 IronToad_UnityProject/Assets/Standard Assets/Effects/TonemappingColorGrading/Editor.meta create mode 100644 IronToad_UnityProject/Assets/Standard Assets/Effects/TonemappingColorGrading/Editor/TonemappingColorGradingEditor.cs create mode 100644 IronToad_UnityProject/Assets/Standard Assets/Effects/TonemappingColorGrading/Editor/TonemappingColorGradingEditor.cs.meta create mode 100644 IronToad_UnityProject/Assets/Standard Assets/Effects/TonemappingColorGrading/Helpers.meta create mode 100644 IronToad_UnityProject/Assets/Standard Assets/Effects/TonemappingColorGrading/Helpers/NeutralLUT16.png create mode 100644 IronToad_UnityProject/Assets/Standard Assets/Effects/TonemappingColorGrading/Helpers/NeutralLUT16.png.meta create mode 100644 IronToad_UnityProject/Assets/Standard Assets/Effects/TonemappingColorGrading/Helpers/NeutralLUT32.png create mode 100644 IronToad_UnityProject/Assets/Standard Assets/Effects/TonemappingColorGrading/Helpers/NeutralLUT32.png.meta create mode 100644 IronToad_UnityProject/Assets/Standard Assets/Effects/TonemappingColorGrading/Resources.meta create mode 100644 IronToad_UnityProject/Assets/Standard Assets/Effects/TonemappingColorGrading/Resources/HistogramCompute.compute create mode 100644 IronToad_UnityProject/Assets/Standard Assets/Effects/TonemappingColorGrading/Resources/HistogramCompute.compute.meta create mode 100644 IronToad_UnityProject/Assets/Standard Assets/Effects/TonemappingColorGrading/Resources/HistogramRender.shader create mode 100644 IronToad_UnityProject/Assets/Standard Assets/Effects/TonemappingColorGrading/Resources/HistogramRender.shader.meta create mode 100644 IronToad_UnityProject/Assets/Standard Assets/Effects/TonemappingColorGrading/Resources/TonemappingColorGrading.cginc create mode 100644 IronToad_UnityProject/Assets/Standard Assets/Effects/TonemappingColorGrading/Resources/TonemappingColorGrading.cginc.meta create mode 100644 IronToad_UnityProject/Assets/Standard Assets/Effects/TonemappingColorGrading/Resources/TonemappingColorGrading.shader create mode 100644 IronToad_UnityProject/Assets/Standard Assets/Effects/TonemappingColorGrading/Resources/TonemappingColorGrading.shader.meta create mode 100644 IronToad_UnityProject/Assets/Standard Assets/Effects/TonemappingColorGrading/TonemappingColorGrading.cs create mode 100644 IronToad_UnityProject/Assets/Standard Assets/Effects/TonemappingColorGrading/TonemappingColorGrading.cs.meta diff --git a/IronToad_UnityProject/Assets/Art/Models/lightHouse_LOW.obj.meta b/IronToad_UnityProject/Assets/Art/Models/lightHouse_LOW.obj.meta deleted file mode 100644 index d94fc60..0000000 --- a/IronToad_UnityProject/Assets/Art/Models/lightHouse_LOW.obj.meta +++ /dev/null @@ -1,82 +0,0 @@ -fileFormatVersion: 2 -guid: 919eb0dba9aa0da44aec3a80f1cf98ea -timeCreated: 1485000000 -licenseType: Free -ModelImporter: - serializedVersion: 19 - fileIDToRecycleName: - 100000: lighthouse - 100002: //RootNode - 400000: lighthouse - 400002: //RootNode - 2300000: lighthouse - 3300000: lighthouse - 4300000: lighthouse - materials: - importMaterials: 1 - materialName: 0 - materialSearch: 1 - animations: - legacyGenerateAnimations: 4 - bakeSimulation: 0 - resampleCurves: 1 - optimizeGameObjects: 0 - motionNodeName: - animationImportErrors: - animationImportWarnings: - animationRetargetingWarnings: - animationDoRetargetingWarnings: 0 - animationCompression: 1 - animationRotationError: 0.5 - animationPositionError: 0.5 - animationScaleError: 0.5 - animationWrapMode: 0 - extraExposedTransformPaths: [] - clipAnimations: [] - isReadable: 1 - meshes: - lODScreenPercentages: [] - globalScale: 1 - meshCompression: 0 - addColliders: 0 - importBlendShapes: 1 - swapUVChannels: 0 - generateSecondaryUV: 0 - useFileUnits: 1 - optimizeMeshForGPU: 1 - keepQuads: 0 - weldVertices: 1 - secondaryUVAngleDistortion: 8 - secondaryUVAreaDistortion: 15.000001 - secondaryUVHardAngle: 88 - secondaryUVPackMargin: 4 - useFileScale: 1 - tangentSpace: - normalSmoothAngle: 60 - normalImportMode: 0 - tangentImportMode: 3 - importAnimation: 1 - copyAvatar: 0 - humanDescription: - serializedVersion: 2 - human: [] - skeleton: [] - armTwist: 0.5 - foreArmTwist: 0.5 - upperLegTwist: 0.5 - legTwist: 0.5 - armStretch: 0.05 - legStretch: 0.05 - feetSpacing: 0 - rootMotionBoneName: - rootMotionBoneRotation: {x: 0, y: 0, z: 0, w: 1} - hasTranslationDoF: 0 - hasExtraRoot: 0 - skeletonHasParents: 1 - lastHumanDescriptionAvatarSource: {instanceID: 0} - animationType: 0 - humanoidOversampling: 1 - additionalBone: 0 - userData: - assetBundleName: - assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Scripts/AlertController.cs b/IronToad_UnityProject/Assets/Scripts/AlertController.cs index 605023d..96f1d04 100644 --- a/IronToad_UnityProject/Assets/Scripts/AlertController.cs +++ b/IronToad_UnityProject/Assets/Scripts/AlertController.cs @@ -9,21 +9,21 @@ public class AlertController : MonoBehaviour public Slider slider; public float hideTime = 5f; - private Vector3 originalPos; - private float lastSpotted; +// private Vector3 originalPos; +// private float lastSpotted; void Start () { NotificationServer.register("spotted boat", spottedBoat); NotificationServer.register("lost boat", lostBoat); - originalPos = text.rectTransform.anchoredPosition3D; +// originalPos = text.rectTransform.anchoredPosition3D; } public void spottedBoat() { LeanTween.cancel(text.gameObject, false); LeanTween.cancel(slider.gameObject, false); - lastSpotted = Time.timeSinceLevelLoad; +// lastSpotted = Time.timeSinceLevelLoad; NotificationServer.notify("show AlertText"); text.text = "hide!"; setTimer(0f); diff --git a/IronToad_UnityProject/Assets/Scripts/Boulder.cs b/IronToad_UnityProject/Assets/Scripts/Boulder.cs new file mode 100644 index 0000000..6669270 --- /dev/null +++ b/IronToad_UnityProject/Assets/Scripts/Boulder.cs @@ -0,0 +1,16 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +public class Boulder : HeavyObject +{ + + + public override void OnWaterStay(WaterController water,float waveHeight) + { + } + + public override void OnWaterExit(WaterController water) + { + } +} diff --git a/IronToad_UnityProject/Assets/Scripts/Boulder.cs.meta b/IronToad_UnityProject/Assets/Scripts/Boulder.cs.meta new file mode 100644 index 0000000..d71ea63 --- /dev/null +++ b/IronToad_UnityProject/Assets/Scripts/Boulder.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: b17436874f6d74be884f5af7ebabda8a +timeCreated: 1485018292 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Scripts/Catapult.cs b/IronToad_UnityProject/Assets/Scripts/Catapult.cs new file mode 100644 index 0000000..dd85e0c --- /dev/null +++ b/IronToad_UnityProject/Assets/Scripts/Catapult.cs @@ -0,0 +1,85 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +using BansheeGz.BGSpline.Components; +using BansheeGz.BGSpline.Curve; + +public class Catapult : MonoBehaviour +{ + public BGCurve splineCurve; + public float speed = 600f; + public float rotateSpeed = 200f; + public float timePadding = 0.5f; + public float timeBetweenLaunches = 0.5f; + public float minScale = 0.3f; + public float maxScale = 1f; + public float randomFactor = 50f; + public AnimationCurve animationCurve; + public Transform player; + + private bool isLaunching = false; + private BGCcCursor splineCursor; + private BGCcCursorObjectTranslate splineObjectTranslate; + private Vector3 originalScale; + private MeshRenderer meshRenderer; + + void Start () + { + splineCursor = splineCurve.GetComponent(); + splineObjectTranslate = splineCurve.GetComponent(); + meshRenderer = splineObjectTranslate.ObjectToManipulate.GetComponent(); + meshRenderer.enabled = false; + + originalScale = splineCurve.transform.parent.localScale; + + NotificationServer.register("statechange Searchlight", searchlightStateChanged); + } + + void Update() + { + splineObjectTranslate.ObjectToManipulate.Rotate(Vector3.forward, Time.deltaTime * rotateSpeed); + } + + public void searchlightStateChanged() + { + LeanTween.cancel(splineObjectTranslate.ObjectToManipulate.parent.gameObject, true); + if (Searchlight.state == Searchlight.SearchState.Chasing) + launchBoulder(); + } + + public void launchBoulder() + { + if (Searchlight.state != Searchlight.SearchState.Chasing || isLaunching) + { + isLaunching = false; + return; + } + + isLaunching = true; + LeanTween.delayedCall(splineObjectTranslate.ObjectToManipulate.parent.gameObject, timeBetweenLaunches, ()=>{ + if (Searchlight.state != Searchlight.SearchState.Chasing) + { + isLaunching = false; + return; + } + meshRenderer.enabled = true; + splineCursor.DistanceRatio = 0f; + splineCurve.transform.parent.position = player.position + + Vector3.right * Random.Range(-randomFactor, randomFactor) + + Vector3.forward * Random.Range(-randomFactor, randomFactor); + splineCurve.transform.parent.localEulerAngles = Vector3.up * Random.Range(0f, 360f); + splineCurve.transform.parent.localScale = new Vector3(Random.Range(minScale * originalScale.x, maxScale * originalScale.x), originalScale.y, originalScale.z); + LeanTween.value(splineObjectTranslate.ObjectToManipulate.gameObject, 0f, 1f, splineCursor.Math.GetDistance() / speed) + .setEase(animationCurve) + .setOnUpdate((float val)=>{ + splineCursor.DistanceRatio = val; + }).setOnComplete(()=>{ + splineCursor.DistanceRatio = 0f; + isLaunching = false; + meshRenderer.enabled = false; + launchBoulder(); + }); + }); + } +} diff --git a/IronToad_UnityProject/Assets/Scripts/Catapult.cs.meta b/IronToad_UnityProject/Assets/Scripts/Catapult.cs.meta new file mode 100644 index 0000000..c0ee060 --- /dev/null +++ b/IronToad_UnityProject/Assets/Scripts/Catapult.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 8d68d4df0b2854bf6bc9e40235372a0f +timeCreated: 1485013470 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Scripts/Lighthouse.cs b/IronToad_UnityProject/Assets/Scripts/Lighthouse.cs index 256ecf8..3805c6f 100644 --- a/IronToad_UnityProject/Assets/Scripts/Lighthouse.cs +++ b/IronToad_UnityProject/Assets/Scripts/Lighthouse.cs @@ -32,7 +32,7 @@ public class Lighthouse : MonoBehaviour { BGCurvePointI point = splineCurve.Points[i]; float distance = 0f; - Vector3 temp = splineCursor.Math.CalcPositionByClosestPoint(point.PositionWorld, out distance); + splineCursor.Math.CalcPositionByClosestPoint(point.PositionWorld, out distance); splineDistantPoints.Add(distance); } splineDistantPoints.Add(splineCursor.Math.GetDistance()); diff --git a/IronToad_UnityProject/Assets/Scripts/ScreenEffects.cs b/IronToad_UnityProject/Assets/Scripts/ScreenEffects.cs new file mode 100644 index 0000000..8537e45 --- /dev/null +++ b/IronToad_UnityProject/Assets/Scripts/ScreenEffects.cs @@ -0,0 +1,52 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +using UnityStandardAssets.CinematicEffects; + +public class ScreenEffects : MonoBehaviour +{ + public DepthOfField depthOfField; + + private float originalNearRadius; + private float originalFarRadius; + + void Start () + { + depthOfField = GetComponent(); + if (depthOfField == null) + depthOfField = gameObject.AddComponent(); + originalNearRadius = depthOfField.focus.nearBlurRadius; + originalFarRadius = depthOfField.focus.farBlurRadius; + + NotificationServer.register("show GameUI", showGame); + NotificationServer.register("hide GameUI", hideGame); + } + + public void showGame() + { + LeanTween.cancel(gameObject, false); + float startNear = depthOfField.focus.nearBlurRadius; + float startFar = depthOfField.focus.farBlurRadius; + DepthOfField.FocusSettings focus = depthOfField.focus; + LeanTween.value(gameObject, 1f, 0f, 0.5f).setEaseInOutQuad().setOnUpdate((float val)=>{ + focus.nearBlurRadius = startNear * val; + focus.farBlurRadius = startFar * val; + }).setOnComplete(()=>{ + depthOfField.enabled = false; + }).setIgnoreTimeScale(true); + } + + public void hideGame() + { + LeanTween.cancel(gameObject, false); + depthOfField.enabled = true; + float startNear = depthOfField.focus.nearBlurRadius; + float startFar = depthOfField.focus.farBlurRadius; + DepthOfField.FocusSettings focus = depthOfField.focus; + LeanTween.value(gameObject, 0f, 1f, 0.5f).setEaseInOutQuad().setOnUpdate((float val)=>{ + focus.nearBlurRadius = startNear + (originalNearRadius-startNear) * val; + focus.farBlurRadius = startFar + (originalFarRadius-startFar) * val; + }).setIgnoreTimeScale(true); + } + +} diff --git a/IronToad_UnityProject/Assets/Scripts/ScreenEffects.cs.meta b/IronToad_UnityProject/Assets/Scripts/ScreenEffects.cs.meta new file mode 100644 index 0000000..04c5a10 --- /dev/null +++ b/IronToad_UnityProject/Assets/Scripts/ScreenEffects.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 0bbf215cb5bca4fa09f6547f0a24f318 +timeCreated: 1485020054 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Scripts/Searchlight.cs b/IronToad_UnityProject/Assets/Scripts/Searchlight.cs index f113fae..0b1f08b 100644 --- a/IronToad_UnityProject/Assets/Scripts/Searchlight.cs +++ b/IronToad_UnityProject/Assets/Scripts/Searchlight.cs @@ -36,7 +36,6 @@ public class Searchlight : MonoBehaviour void Awake() { - NotificationServer.register("statechange Searchlight", stateChanged); NotificationServer.register("statechange Searchlight safe", stateSafe); NotificationServer.register("statechange Searchlight returning", stateReturning); if (!instants.Contains(this)) @@ -56,6 +55,8 @@ public class Searchlight : MonoBehaviour NotificationServer.notify("statechange Searchlight"); NotificationServer.notify("chasing boat"); } + LeanTween.cancel(gameObject, false); + LeanTween.move(gameObject, chased.transform.position, 0.5f).setEase(animationCurve).setOnComplete(chase); NotificationServer.notify("spotted boat"); } @@ -88,8 +89,8 @@ public class Searchlight : MonoBehaviour public void stateChanged() { LeanTween.cancel(gameObject, false); - if (state == SearchState.Chasing) - LeanTween.move(gameObject, chased.transform.position, 0.5f).setEase(animationCurve).setOnComplete(chase); +// if (state == SearchState.Chasing) +// LeanTween.move(gameObject, chased.transform.position, 0.5f).setEase(animationCurve).setOnComplete(chase); } public void chase() diff --git a/IronToad_UnityProject/Assets/Scripts/UIPanel.cs b/IronToad_UnityProject/Assets/Scripts/UIPanel.cs index 5e7c4b1..3135ea3 100644 --- a/IronToad_UnityProject/Assets/Scripts/UIPanel.cs +++ b/IronToad_UnityProject/Assets/Scripts/UIPanel.cs @@ -30,7 +30,7 @@ public class UIPanel : MonoBehaviour private RectTransform rectTransform; private CanvasGroup canvasGroup; private Vector3 originalPos; - private bool isShowing = false; +// private bool isShowing = false; void Awake () { @@ -143,7 +143,7 @@ public class UIPanel : MonoBehaviour canvasGroup.alpha = 1f; rectTransform.anchoredPosition3D = originalPos; transform.localScale = Vector3.one; - isShowing = true; +// isShowing = true; } public void setHideState() @@ -151,7 +151,7 @@ public class UIPanel : MonoBehaviour canvasGroup.interactable = false; canvasGroup.blocksRaycasts = false; canvasGroup.alpha = 0f; - isShowing = false; +// isShowing = false; } public void quitApplication() diff --git a/IronToad_UnityProject/Assets/Sound.meta b/IronToad_UnityProject/Assets/Sound.meta new file mode 100644 index 0000000..359da3b --- /dev/null +++ b/IronToad_UnityProject/Assets/Sound.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 0fbabcae9313543ffbf1429aeac3664d +folderAsset: yes +timeCreated: 1485006712 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/AmbientOcclusion.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/AmbientOcclusion.meta new file mode 100644 index 0000000..e556049 --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/AmbientOcclusion.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: ed6d7947a564a4dd1987f60392be4349 +folderAsset: yes +timeCreated: 1457326591 +licenseType: Store +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/AmbientOcclusion/AmbientOcclusion.cs b/IronToad_UnityProject/Assets/Standard Assets/Effects/AmbientOcclusion/AmbientOcclusion.cs new file mode 100644 index 0000000..1093cbc --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/AmbientOcclusion/AmbientOcclusion.cs @@ -0,0 +1,360 @@ +using UnityEngine; +using UnityEngine.Rendering; + +namespace UnityStandardAssets.CinematicEffects +{ + [ExecuteInEditMode] + [RequireComponent(typeof(Camera))] + [AddComponentMenu("Image Effects/Cinematic/Ambient Occlusion")] +#if UNITY_5_4_OR_NEWER + [ImageEffectAllowedInSceneView] +#endif + public partial class AmbientOcclusion : MonoBehaviour + { + #region Public Properties + + /// Effect settings. + [SerializeField] + public Settings settings = Settings.defaultSettings; + + /// Checks if the ambient-only mode is supported under the current settings. + public bool isAmbientOnlySupported + { + get { return targetCamera.hdr && occlusionSource == OcclusionSource.GBuffer; } + } + + /// Checks if the G-buffer is available + public bool isGBufferAvailable + { + get { return targetCamera.actualRenderingPath == RenderingPath.DeferredShading; } + } + + #endregion + + #region Private Properties + + // Properties referring to the current settings + + float intensity + { + get { return settings.intensity; } + } + + float radius + { + get { return Mathf.Max(settings.radius, 1e-4f); } + } + + SampleCount sampleCount + { + get { return settings.sampleCount; } + } + + int sampleCountValue + { + get + { + switch (settings.sampleCount) + { + case SampleCount.Lowest: return 3; + case SampleCount.Low: return 6; + case SampleCount.Medium: return 12; + case SampleCount.High: return 20; + } + return Mathf.Clamp(settings.sampleCountValue, 1, 256); + } + } + + OcclusionSource occlusionSource + { + get + { + if (settings.occlusionSource == OcclusionSource.GBuffer && !isGBufferAvailable) + // An unavailable source was chosen: fallback to DepthNormalsTexture. + return OcclusionSource.DepthNormalsTexture; + else + return settings.occlusionSource; + } + } + + bool downsampling + { + get { return settings.downsampling; } + } + + bool ambientOnly + { + get { return settings.ambientOnly && !settings.debug && isAmbientOnlySupported; } + } + + // Texture format used for storing AO + RenderTextureFormat aoTextureFormat + { + get + { + if (SystemInfo.SupportsRenderTextureFormat(RenderTextureFormat.R8)) + return RenderTextureFormat.R8; + else + return RenderTextureFormat.Default; + } + } + + // AO shader + Shader aoShader + { + get + { + if (_aoShader == null) + _aoShader = Shader.Find("Hidden/Image Effects/Cinematic/AmbientOcclusion"); + return _aoShader; + } + } + + [SerializeField] Shader _aoShader; + + // Temporary aterial for the AO shader + Material aoMaterial + { + get + { + if (_aoMaterial == null) + _aoMaterial = ImageEffectHelper.CheckShaderAndCreateMaterial(aoShader); + return _aoMaterial; + } + } + + Material _aoMaterial; + + // Command buffer for the AO pass + CommandBuffer aoCommands + { + get + { + if (_aoCommands == null) + { + _aoCommands = new CommandBuffer(); + _aoCommands.name = "AmbientOcclusion"; + } + return _aoCommands; + } + } + + CommandBuffer _aoCommands; + + // Target camera + Camera targetCamera + { + get { return GetComponent(); } + } + + // Property observer + PropertyObserver propertyObserver { get; set; } + + // Reference to the quad mesh in the built-in assets + // (used in MRT blitting) + Mesh quadMesh + { + get { return _quadMesh; } + } + + [SerializeField] Mesh _quadMesh; + + #endregion + + #region Effect Passes + + // Build commands for the AO pass (used in the ambient-only mode). + void BuildAOCommands() + { + var cb = aoCommands; + + var tw = targetCamera.pixelWidth; + var th = targetCamera.pixelHeight; + var ts = downsampling ? 2 : 1; + var format = aoTextureFormat; + var rwMode = RenderTextureReadWrite.Linear; + var filter = FilterMode.Bilinear; + + // AO buffer + var m = aoMaterial; + var rtMask = Shader.PropertyToID("_OcclusionTexture"); + cb.GetTemporaryRT(rtMask, tw / ts, th / ts, 0, filter, format, rwMode); + + // AO estimation + cb.Blit((Texture)null, rtMask, m, 2); + + // Blur buffer + var rtBlur = Shader.PropertyToID("_OcclusionBlurTexture"); + + // Primary blur filter (large kernel) + cb.GetTemporaryRT(rtBlur, tw, th, 0, filter, format, rwMode); + cb.SetGlobalVector("_BlurVector", Vector2.right * 2); + cb.Blit(rtMask, rtBlur, m, 4); + cb.ReleaseTemporaryRT(rtMask); + + cb.GetTemporaryRT(rtMask, tw, th, 0, filter, format, rwMode); + cb.SetGlobalVector("_BlurVector", Vector2.up * 2 * ts); + cb.Blit(rtBlur, rtMask, m, 4); + cb.ReleaseTemporaryRT(rtBlur); + + // Secondary blur filter (small kernel) + cb.GetTemporaryRT(rtBlur, tw, th, 0, filter, format, rwMode); + cb.SetGlobalVector("_BlurVector", Vector2.right * ts); + cb.Blit(rtMask, rtBlur, m, 6); + cb.ReleaseTemporaryRT(rtMask); + + cb.GetTemporaryRT(rtMask, tw, th, 0, filter, format, rwMode); + cb.SetGlobalVector("_BlurVector", Vector2.up * ts); + cb.Blit(rtBlur, rtMask, m, 6); + cb.ReleaseTemporaryRT(rtBlur); + + // Combine AO to the G-buffer. + var mrt = new RenderTargetIdentifier[] { + BuiltinRenderTextureType.GBuffer0, // Albedo, Occ + BuiltinRenderTextureType.CameraTarget // Ambient + }; + cb.SetRenderTarget(mrt, BuiltinRenderTextureType.CameraTarget); + cb.SetGlobalTexture("_OcclusionTexture", rtMask); + cb.DrawMesh(quadMesh, Matrix4x4.identity, m, 0, 8); + + cb.ReleaseTemporaryRT(rtMask); + } + + // Execute the AO pass immediately (used in the forward mode). + void ExecuteAOPass(RenderTexture source, RenderTexture destination) + { + var tw = source.width; + var th = source.height; + var ts = downsampling ? 2 : 1; + var format = aoTextureFormat; + var rwMode = RenderTextureReadWrite.Linear; + var useGBuffer = settings.occlusionSource == OcclusionSource.GBuffer; + + // AO buffer + var m = aoMaterial; + var rtMask = RenderTexture.GetTemporary(tw / ts, th / ts, 0, format, rwMode); + + // AO estimation + Graphics.Blit((Texture)null, rtMask, m, (int)occlusionSource); + + // Primary blur filter (large kernel) + var rtBlur = RenderTexture.GetTemporary(tw, th, 0, format, rwMode); + m.SetVector("_BlurVector", Vector2.right * 2); + Graphics.Blit(rtMask, rtBlur, m, useGBuffer ? 4 : 3); + RenderTexture.ReleaseTemporary(rtMask); + + rtMask = RenderTexture.GetTemporary(tw, th, 0, format, rwMode); + m.SetVector("_BlurVector", Vector2.up * 2 * ts); + Graphics.Blit(rtBlur, rtMask, m, useGBuffer ? 4 : 3); + RenderTexture.ReleaseTemporary(rtBlur); + + // Secondary blur filter (small kernel) + rtBlur = RenderTexture.GetTemporary(tw, th, 0, format, rwMode); + m.SetVector("_BlurVector", Vector2.right * ts); + Graphics.Blit(rtMask, rtBlur, m, useGBuffer ? 6 : 5); + RenderTexture.ReleaseTemporary(rtMask); + + rtMask = RenderTexture.GetTemporary(tw, th, 0, format, rwMode); + m.SetVector("_BlurVector", Vector2.up * ts); + Graphics.Blit(rtBlur, rtMask, m, useGBuffer ? 6 : 5); + RenderTexture.ReleaseTemporary(rtBlur); + + // Combine AO with the source. + m.SetTexture("_OcclusionTexture", rtMask); + + if (!settings.debug) + Graphics.Blit(source, destination, m, 7); + else + Graphics.Blit(source, destination, m, 9); + + RenderTexture.ReleaseTemporary(rtMask); + } + + // Update the common material properties. + void UpdateMaterialProperties() + { + var m = aoMaterial; + m.SetFloat("_Intensity", intensity); + m.SetFloat("_Radius", radius); + m.SetFloat("_TargetScale", downsampling ? 0.5f : 1); + m.SetInt("_SampleCount", sampleCountValue); + } + + #endregion + + #region MonoBehaviour Functions + + void OnEnable() + { + // Check if the shader is supported in the current platform. + if (!ImageEffectHelper.IsSupported(aoShader, true, false, this)) + { + enabled = false; + return; + } + + // Register the command buffer if in the ambient-only mode. + if (ambientOnly) + targetCamera.AddCommandBuffer(CameraEvent.BeforeReflections, aoCommands); + + // Enable depth textures which the occlusion source requires. + if (occlusionSource == OcclusionSource.DepthTexture) + targetCamera.depthTextureMode |= DepthTextureMode.Depth; + + if (occlusionSource != OcclusionSource.GBuffer) + targetCamera.depthTextureMode |= DepthTextureMode.DepthNormals; + } + + void OnDisable() + { + // Destroy all the temporary resources. + if (_aoMaterial != null) DestroyImmediate(_aoMaterial); + _aoMaterial = null; + + if (_aoCommands != null) + targetCamera.RemoveCommandBuffer(CameraEvent.BeforeReflections, _aoCommands); + _aoCommands = null; + } + + void Update() + { + if (propertyObserver.CheckNeedsReset(settings, targetCamera)) + { + // Reinitialize all the resources by disabling/enabling itself. + // This is not very efficient way but just works... + OnDisable(); + OnEnable(); + + // Build the command buffer if in the ambient-only mode. + if (ambientOnly) + { + aoCommands.Clear(); + BuildAOCommands(); + } + + propertyObserver.Update(settings, targetCamera); + } + + // Update the material properties (later used in the AO commands). + if (ambientOnly) UpdateMaterialProperties(); + } + + [ImageEffectOpaque] + void OnRenderImage(RenderTexture source, RenderTexture destination) + { + if (ambientOnly) + { + // Do nothing in the ambient-only mode. + Graphics.Blit(source, destination); + } + else + { + // Execute the AO pass. + UpdateMaterialProperties(); + ExecuteAOPass(source, destination); + } + } + + #endregion + } +} diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/AmbientOcclusion/AmbientOcclusion.cs.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/AmbientOcclusion/AmbientOcclusion.cs.meta new file mode 100644 index 0000000..c2329f9 --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/AmbientOcclusion/AmbientOcclusion.cs.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: e89654dcf6db746d2a57aeaaa14f5e83 +timeCreated: 1457327177 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: + - _aoShader: {fileID: 4800000, guid: 65e203e5acda447acbf9dc1ef78c4a39, type: 3} + - _quadMesh: {fileID: 10210, guid: 0000000000000000e000000000000000, type: 0} + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/AmbientOcclusion/Editor.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/AmbientOcclusion/Editor.meta new file mode 100644 index 0000000..024d19a --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/AmbientOcclusion/Editor.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: c1589efc0706e448d9a0af709e2c99cc +folderAsset: yes +timeCreated: 1457326964 +licenseType: Store +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/AmbientOcclusion/Editor/AmbientOcclusionEditor.cs b/IronToad_UnityProject/Assets/Standard Assets/Effects/AmbientOcclusion/Editor/AmbientOcclusionEditor.cs new file mode 100644 index 0000000..636c650 --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/AmbientOcclusion/Editor/AmbientOcclusionEditor.cs @@ -0,0 +1,89 @@ +using UnityEngine; +using UnityEditor; + +namespace UnityStandardAssets.CinematicEffects +{ + [CanEditMultipleObjects] + [CustomEditor(typeof(AmbientOcclusion))] + public class AmbientOcclusionEditor : Editor + { + SerializedProperty _intensity; + SerializedProperty _radius; + SerializedProperty _sampleCount; + SerializedProperty _sampleCountValue; + SerializedProperty _downsampling; + SerializedProperty _occlusionSource; + SerializedProperty _ambientOnly; + SerializedProperty _debug; + + static GUIContent _textValue = new GUIContent("Value"); + + static string _textNoGBuffer = + "G-buffer is currently unavailable. " + + "Change Renderring Path in camera settings to Deferred."; + + static string _textNoAmbientOnly = + "The ambient-only mode is currently disabled; " + + "it requires G-buffer source and HDR rendering."; + + static string _textGBufferNote = + "Forward opaque objects don't go in the G-buffer. " + + "This may lead to artifacts."; + + void OnEnable() + { + _intensity = serializedObject.FindProperty("settings.intensity"); + _radius = serializedObject.FindProperty("settings.radius"); + _sampleCount = serializedObject.FindProperty("settings.sampleCount"); + _sampleCountValue = serializedObject.FindProperty("settings.sampleCountValue"); + _downsampling = serializedObject.FindProperty("settings.downsampling"); + _occlusionSource = serializedObject.FindProperty("settings.occlusionSource"); + _ambientOnly = serializedObject.FindProperty("settings.ambientOnly"); + _debug = serializedObject.FindProperty("settings.debug"); + } + + public override void OnInspectorGUI() + { + var targetInstance = (AmbientOcclusion)target; + + serializedObject.Update(); + + EditorGUILayout.PropertyField(_intensity); + EditorGUILayout.PropertyField(_radius); + EditorGUILayout.PropertyField(_sampleCount); + + if (_sampleCount.hasMultipleDifferentValues || + _sampleCount.enumValueIndex == (int)AmbientOcclusion.SampleCount.Variable) + { + EditorGUI.indentLevel++; + EditorGUILayout.PropertyField(_sampleCountValue, _textValue); + EditorGUI.indentLevel--; + } + + EditorGUILayout.PropertyField(_downsampling); + EditorGUILayout.PropertyField(_occlusionSource); + + if (!_occlusionSource.hasMultipleDifferentValues && + _occlusionSource.enumValueIndex == (int)AmbientOcclusion.OcclusionSource.GBuffer) + { + if (!targetInstance.isGBufferAvailable) + EditorGUILayout.HelpBox(_textNoGBuffer, MessageType.Warning); + else if (!_ambientOnly.hasMultipleDifferentValues && !_ambientOnly.boolValue) + EditorGUILayout.HelpBox(_textGBufferNote, MessageType.Info); + } + + EditorGUILayout.PropertyField(_ambientOnly); + + if (!_ambientOnly.hasMultipleDifferentValues && + _ambientOnly.boolValue && + !targetInstance.isAmbientOnlySupported) + { + EditorGUILayout.HelpBox(_textNoAmbientOnly, MessageType.Warning); + } + + EditorGUILayout.PropertyField(_debug); + + serializedObject.ApplyModifiedProperties(); + } + } +} diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/AmbientOcclusion/Editor/AmbientOcclusionEditor.cs.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/AmbientOcclusion/Editor/AmbientOcclusionEditor.cs.meta new file mode 100644 index 0000000..5ef27d2 --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/AmbientOcclusion/Editor/AmbientOcclusionEditor.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 05ea8e27ed8e74e67a9220b4f4119e51 +timeCreated: 1457327141 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/AmbientOcclusion/Helpers.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/AmbientOcclusion/Helpers.meta new file mode 100644 index 0000000..168a0c9 --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/AmbientOcclusion/Helpers.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 1d775599023574a39befabe47bdfddde +folderAsset: yes +timeCreated: 1457326936 +licenseType: Store +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/AmbientOcclusion/Helpers/PropertyObserver.cs b/IronToad_UnityProject/Assets/Standard Assets/Effects/AmbientOcclusion/Helpers/PropertyObserver.cs new file mode 100644 index 0000000..270368f --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/AmbientOcclusion/Helpers/PropertyObserver.cs @@ -0,0 +1,44 @@ +using UnityEngine; + +namespace UnityStandardAssets.CinematicEffects +{ + public partial class AmbientOcclusion : MonoBehaviour + { + // Observer class that detects changes on properties + struct PropertyObserver + { + // AO properties + bool _downsampling; + OcclusionSource _occlusionSource; + bool _ambientOnly; + bool _debug; + + // Camera properties + int _pixelWidth; + int _pixelHeight; + + // Check if it has to reset itself for property changes. + public bool CheckNeedsReset(Settings setting, Camera camera) + { + return + _downsampling != setting.downsampling || + _occlusionSource != setting.occlusionSource || + _ambientOnly != setting.ambientOnly || + _debug != setting.debug || + _pixelWidth != camera.pixelWidth || + _pixelHeight != camera.pixelHeight; + } + + // Update the internal state. + public void Update(Settings setting, Camera camera) + { + _downsampling = setting.downsampling; + _occlusionSource = setting.occlusionSource; + _ambientOnly = setting.ambientOnly; + _debug = setting.debug; + _pixelWidth = camera.pixelWidth; + _pixelHeight = camera.pixelHeight; + } + } + } +} diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/AmbientOcclusion/Helpers/PropertyObserver.cs.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/AmbientOcclusion/Helpers/PropertyObserver.cs.meta new file mode 100644 index 0000000..21830ef --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/AmbientOcclusion/Helpers/PropertyObserver.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 1d9548d9a173a40e4b758ecf6e4fed49 +timeCreated: 1457326885 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/AmbientOcclusion/Helpers/Settings.cs b/IronToad_UnityProject/Assets/Standard Assets/Effects/AmbientOcclusion/Helpers/Settings.cs new file mode 100644 index 0000000..9d96d26 --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/AmbientOcclusion/Helpers/Settings.cs @@ -0,0 +1,85 @@ +using System; +using UnityEngine; + +namespace UnityStandardAssets.CinematicEffects +{ + public partial class AmbientOcclusion : MonoBehaviour + { + /// Values for Settings.sampleCount, determining the number of sample points. + public enum SampleCount + { + Lowest, Low, Medium, High, Variable + } + + /// Values for Settings.occlusionSource, determining the source buffer of occlusion. + public enum OcclusionSource + { + DepthTexture, DepthNormalsTexture, GBuffer + } + + /// Class used for storing settings of AmbientOcclusion. + [Serializable] + public class Settings + { + /// Degree of darkness produced by the effect. + [SerializeField, Range(0, 4)] + [Tooltip("Degree of darkness produced by the effect.")] + public float intensity; + + /// Radius of sample points, which affects extent of darkened areas. + [SerializeField] + [Tooltip("Radius of sample points, which affects extent of darkened areas.")] + public float radius; + + /// Number of sample points, which affects quality and performance. + [SerializeField] + [Tooltip("Number of sample points, which affects quality and performance.")] + public SampleCount sampleCount; + + /// Determines the sample count when SampleCount.Variable is used. + [SerializeField] + [Tooltip("Determines the sample count when SampleCount.Variable is used.")] + public int sampleCountValue; + + /// Halves the resolution of the effect to increase performance. + [SerializeField] + [Tooltip("Halves the resolution of the effect to increase performance.")] + public bool downsampling; + + /// Enables the ambient-only mode in that the effect only affects + /// ambient lighting. This mode is only available with G-buffer + /// source and HDR rendering. + [SerializeField] + [Tooltip("If checked, the effect only affects ambient lighting.")] + public bool ambientOnly; + + /// Source buffer on which the occlusion estimator is based. + [SerializeField] + [Tooltip("Source buffer on which the occlusion estimator is based.")] + public OcclusionSource occlusionSource; + + /// Displays occlusion for debug purpose. + [SerializeField] + [Tooltip("Displays occlusion for debug purpose.")] + public bool debug; + + /// Returns the default settings. + public static Settings defaultSettings + { + get + { + return new Settings + { + intensity = 1, + radius = 0.3f, + sampleCount = SampleCount.Medium, + sampleCountValue = 24, + downsampling = false, + ambientOnly = false, + occlusionSource = OcclusionSource.DepthNormalsTexture + }; + } + } + } + } +} diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/AmbientOcclusion/Helpers/Settings.cs.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/AmbientOcclusion/Helpers/Settings.cs.meta new file mode 100644 index 0000000..438495e --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/AmbientOcclusion/Helpers/Settings.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: e952a344c72354904a417d27abe6f55e +timeCreated: 1457331804 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/AmbientOcclusion/Resources.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/AmbientOcclusion/Resources.meta new file mode 100644 index 0000000..4c04e73 --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/AmbientOcclusion/Resources.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: ae08100d29090452888e1b6a7b5a7170 +folderAsset: yes +timeCreated: 1457326958 +licenseType: Store +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/AmbientOcclusion/Resources/AmbientOcclusion.cginc b/IronToad_UnityProject/Assets/Standard Assets/Effects/AmbientOcclusion/Resources/AmbientOcclusion.cginc new file mode 100644 index 0000000..ef722db --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/AmbientOcclusion/Resources/AmbientOcclusion.cginc @@ -0,0 +1,409 @@ +// Upgrade NOTE: commented out 'float4x4 _WorldToCamera', a built-in variable +// Upgrade NOTE: replaced '_WorldToCamera' with 'unity_WorldToCamera' + +// -------- +// Additional options for further customization +// -------- + +// By default, a fixed sampling pattern is used in the AO estimator. +// Although this gives preferable results in most cases, a completely +// random sampling pattern could give aesthetically good results in some +// cases. Comment out the line below to use the random pattern instead of +// the fixed one. +#define FIXED_SAMPLING_PATTERN 1 + +// The constant below determines the contrast of occlusion. Altough this +// allows intentional over/under occlusion, currently is not exposed to the +// editor, because it’s thought to be rarely useful. +static const float kContrast = 0.6; + +// The constant below controls the geometry-awareness of the blur filter. +// The higher value, the more sensitive it is. +static const float kGeom = 50; + +// The constants below are used in the AO estimator. Beta is mainly used +// for suppressing self-shadowing noise, and Epsilon is used to prevent +// calculation underflow. See the paper (Morgan 2011 http://goo.gl/2iz3P) +// for further details of these constants. +static const float kBeta = 0.002; +static const float kEpsilon = 1e-4; + +// -------- + +#include "UnityCG.cginc" + +// Global shader properties +sampler2D _CameraGBufferTexture2; +sampler2D_float _CameraDepthTexture; +sampler2D _CameraDepthNormalsTexture; +// float4x4 _WorldToCamera; + +// Sample count +// Use a constant on GLES2 (basically it doesn't support dynamic looping). +#if SHADER_API_GLES +static const int _SampleCount = 5; +#else +int _SampleCount; +#endif + +sampler2D _MainTex; +float4 _MainTex_TexelSize; +sampler2D _OcclusionTexture; + +// Material shader properties +half _Intensity; +float _Radius; +float _TargetScale; +float2 _BlurVector; + +// Utility for sin/cos +float2 CosSin(float theta) +{ + float sn, cs; + sincos(theta, sn, cs); + return float2(cs, sn); +} + +// Gamma encoding function for AO value +// (do nothing if in the linear mode) +half EncodeAO(half x) +{ + // Gamma encoding + half x_g = 1 - pow(1 - x, 1 / 2.2); + // ColorSpaceLuminance.w is 0 (gamma) or 1 (linear). + return lerp(x_g, x, unity_ColorSpaceLuminance.w); +} + +// Pseudo random number generator with 2D argument +float UVRandom(float u, float v) +{ + float f = dot(float2(12.9898, 78.233), float2(u, v)); + return frac(43758.5453 * sin(f)); +} + +// Interleaved gradient function from Jimenez 2014 http://goo.gl/eomGso +float GradientNoise(float2 uv) +{ + uv = floor(uv * _ScreenParams.xy); + float f = dot(float2(0.06711056f, 0.00583715f), uv); + return frac(52.9829189f * frac(f)); +} + +// Boundary check for depth sampler +// (returns a very large value if it lies out of bounds) +float CheckBounds(float2 uv, float d) +{ + float ob = any(uv < 0) + any(uv > 1); +#if defined(UNITY_REVERSED_Z) + ob += (d <= 0.00001); +#else + ob += (d >= 0.99999); +#endif + return ob * 1e8; +} + +// Depth/normal sampling functions +float SampleDepth(float2 uv) +{ +#if SOURCE_GBUFFER || SOURCE_DEPTH + float d = SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, uv); + return LinearEyeDepth(d) + CheckBounds(uv, d); +#else + float4 cdn = tex2D(_CameraDepthNormalsTexture, uv); + float d = DecodeFloatRG(cdn.zw); + return d * _ProjectionParams.z + CheckBounds(uv, d); +#endif +} + +float3 SampleNormal(float2 uv) +{ +#if SOURCE_GBUFFER + float3 norm = tex2D(_CameraGBufferTexture2, uv).xyz; + norm = norm * 2 - any(norm); // gets (0,0,0) when norm == 0 + return mul((float3x3)unity_WorldToCamera, norm); +#else + float4 cdn = tex2D(_CameraDepthNormalsTexture, uv); + return DecodeViewNormalStereo(cdn) * float3(1, 1, -1); +#endif +} + +float SampleDepthNormal(float2 uv, out float3 normal) +{ +#if SOURCE_GBUFFER || SOURCE_DEPTH + normal = SampleNormal(uv); + return SampleDepth(uv); +#else + float4 cdn = tex2D(_CameraDepthNormalsTexture, uv); + normal = DecodeViewNormalStereo(cdn) * float3(1, 1, -1); + float d = DecodeFloatRG(cdn.zw); + return d * _ProjectionParams.z + CheckBounds(uv, d); +#endif +} + +// Reconstruct view-space position from UV and depth. +// p11_22 = (unity_CameraProjection._11, unity_CameraProjection._22) +// p13_31 = (unity_CameraProjection._13, unity_CameraProjection._23) +float3 ReconstructViewPos(float2 uv, float depth, float2 p11_22, float2 p13_31) +{ + return float3((uv * 2 - 1 - p13_31) / p11_22, 1) * depth; +} + +// Normal vector comparer (for geometry-aware weighting) +half CompareNormal(half3 d1, half3 d2) +{ + return pow((dot(d1, d2) + 1) * 0.5, kGeom); +} + +// Final combiner function +half3 CombineOcclusion(half3 src, half3 ao) +{ + return lerp(src, 0, EncodeAO(ao)); +} + +// Sample point picker +float3 PickSamplePoint(float2 uv, float index) +{ + // Uniformaly distributed points on a unit sphere http://goo.gl/X2F1Ho +#if FIXED_SAMPLING_PATTERN + float gn = GradientNoise(uv * _TargetScale); + float u = frac(UVRandom(0, index) + gn) * 2 - 1; + float theta = (UVRandom(1, index) + gn) * UNITY_PI * 2; +#else + float u = UVRandom(uv.x + _Time.x, uv.y + index) * 2 - 1; + float theta = UVRandom(-uv.x - _Time.x, uv.y + index) * UNITY_PI * 2; +#endif + float3 v = float3(CosSin(theta) * sqrt(1 - u * u), u); + // Make them distributed between [0, _Radius] + float l = sqrt((index + 1) / _SampleCount) * _Radius; + return v * l; +} + +// Occlusion estimator function +float EstimateOcclusion(float2 uv) +{ + // Parameters used in coordinate conversion + float3x3 proj = (float3x3)unity_CameraProjection; + float2 p11_22 = float2(unity_CameraProjection._11, unity_CameraProjection._22); + float2 p13_31 = float2(unity_CameraProjection._13, unity_CameraProjection._23); + + // View space normal and depth + float3 norm_o; + float depth_o = SampleDepthNormal(uv, norm_o); + +#if SOURCE_DEPTHNORMALS + // Offset the depth value to avoid precision error. + // (depth in the DepthNormals mode has only 16-bit precision) + depth_o -= _ProjectionParams.z / 65536; +#endif + + // Reconstruct the view-space position. + float3 vpos_o = ReconstructViewPos(uv, depth_o, p11_22, p13_31); + + // Distance-based AO estimator based on Morgan 2011 http://goo.gl/2iz3P + float ao = 0.0; + + for (int s = 0; s < _SampleCount; s++) + { + // Sample point +#if SHADER_API_D3D11 + // This 'floor(1.0001 * s)' operation is needed to avoid a NVidia + // shader issue. This issue is only observed on DX11. + float3 v_s1 = PickSamplePoint(uv, floor(1.0001 * s)); +#else + float3 v_s1 = PickSamplePoint(uv, s); +#endif + v_s1 = faceforward(v_s1, -norm_o, v_s1); + float3 vpos_s1 = vpos_o + v_s1; + + // Reproject the sample point + float3 spos_s1 = mul(proj, vpos_s1); + float2 uv_s1 = (spos_s1.xy / vpos_s1.z + 1) * 0.5; + + // Depth at the sample point + float depth_s1 = SampleDepth(uv_s1); + + // Relative position of the sample point + float3 vpos_s2 = ReconstructViewPos(uv_s1, depth_s1, p11_22, p13_31); + float3 v_s2 = vpos_s2 - vpos_o; + + // Estimate the obscurance value + float a1 = max(dot(v_s2, norm_o) - kBeta * depth_o, 0); + float a2 = dot(v_s2, v_s2) + kEpsilon; + ao += a1 / a2; + } + + ao *= _Radius; // intensity normalization + + // Apply other parameters. + return pow(ao * _Intensity / _SampleCount, kContrast); +} + +// Geometry-aware separable blur filter (large kernel) +half SeparableBlurLarge(sampler2D tex, float2 uv, float2 delta) +{ +#if !SHADER_API_MOBILE + // 9-tap Gaussian blur with adaptive sampling + float2 uv1a = uv - delta; + float2 uv1b = uv + delta; + float2 uv2a = uv - delta * 2; + float2 uv2b = uv + delta * 2; + float2 uv3a = uv - delta * 3.2307692308; + float2 uv3b = uv + delta * 3.2307692308; + + half3 n0 = SampleNormal(uv); + + half w0 = 0.37004405286; + half w1a = CompareNormal(n0, SampleNormal(uv1a)) * 0.31718061674; + half w1b = CompareNormal(n0, SampleNormal(uv1b)) * 0.31718061674; + half w2a = CompareNormal(n0, SampleNormal(uv2a)) * 0.19823788546; + half w2b = CompareNormal(n0, SampleNormal(uv2b)) * 0.19823788546; + half w3a = CompareNormal(n0, SampleNormal(uv3a)) * 0.11453744493; + half w3b = CompareNormal(n0, SampleNormal(uv3b)) * 0.11453744493; + + half s = tex2D(_MainTex, uv).r * w0; + s += tex2D(_MainTex, uv1a).r * w1a; + s += tex2D(_MainTex, uv1b).r * w1b; + s += tex2D(_MainTex, uv2a).r * w2a; + s += tex2D(_MainTex, uv2b).r * w2b; + s += tex2D(_MainTex, uv3a).r * w3a; + s += tex2D(_MainTex, uv3b).r * w3b; + + return s / (w0 + w1a + w1b + w2a + w2b + w3a + w3b); +#else + // 9-tap Gaussian blur with linear sampling + // (less quality but slightly fast) + float2 uv1a = uv - delta * 1.3846153846; + float2 uv1b = uv + delta * 1.3846153846; + float2 uv2a = uv - delta * 3.2307692308; + float2 uv2b = uv + delta * 3.2307692308; + + half3 n0 = SampleNormal(uv); + + half w0 = 0.2270270270; + half w1a = CompareNormal(n0, SampleNormal(uv1a)) * 0.3162162162; + half w1b = CompareNormal(n0, SampleNormal(uv1b)) * 0.3162162162; + half w2a = CompareNormal(n0, SampleNormal(uv2a)) * 0.0702702703; + half w2b = CompareNormal(n0, SampleNormal(uv2b)) * 0.0702702703; + + half s = tex2D(_MainTex, uv).r * w0; + s += tex2D(_MainTex, uv1a).r * w1a; + s += tex2D(_MainTex, uv1b).r * w1b; + s += tex2D(_MainTex, uv2a).r * w2a; + s += tex2D(_MainTex, uv2b).r * w2b; + + return s / (w0 + w1a + w1b + w2a + w2b); +#endif +} + +// Geometry-aware separable blur filter (small kernel) +half SeparableBlurSmall(sampler2D tex, float2 uv, float2 delta) +{ + float2 uv1 = uv - delta; + float2 uv2 = uv + delta; + + half3 n0 = SampleNormal(uv); + + half w0 = 2; + half w1 = CompareNormal(n0, SampleNormal(uv1)); + half w2 = CompareNormal(n0, SampleNormal(uv2)); + + half s = tex2D(_MainTex, uv).r * w0; + s += tex2D(_MainTex, uv1).r * w1; + s += tex2D(_MainTex, uv2).r * w2; + + return s / (w0 + w1 + w2); +} + +// Occlusion estimation pass +half4 frag_ao(v2f_img i) : SV_Target +{ + return EstimateOcclusion(i.uv); +} + +// Noise reduction pass (large kernel) +half4 frag_blur1(v2f_img i) : SV_Target +{ + float2 delta = _MainTex_TexelSize.xy * _BlurVector; + return SeparableBlurLarge(_MainTex, i.uv, delta); +} + +// Noise reduction pass (small kernel) +half4 frag_blur2(v2f_img i) : SV_Target +{ + float2 delta = _MainTex_TexelSize.xy * _BlurVector; + return SeparableBlurSmall(_MainTex, i.uv, delta); +} + +// Combiner pass for the forward mode +struct v2f_multitex +{ + float4 pos : SV_POSITION; + float2 uv0 : TEXCOORD0; + float2 uv1 : TEXCOORD1; +}; + +v2f_multitex vert_multitex(appdata_img v) +{ + // Handles vertically-flipped case. + float vflip = sign(_MainTex_TexelSize.y); + + v2f_multitex o; + o.pos = mul(UNITY_MATRIX_MVP, v.vertex); + o.uv0 = v.texcoord.xy; + o.uv1 = (v.texcoord.xy - 0.5) * float2(1, vflip) + 0.5; + return o; +} + +half4 frag_combine(v2f_multitex i) : SV_Target +{ + half4 src = tex2D(_MainTex, i.uv0); + half ao = tex2D(_OcclusionTexture, i.uv1).r; + return half4(CombineOcclusion(src.rgb, ao), src.a); +} + +// Combiner pass for the ambient-only mode +v2f_img vert_gbuffer(appdata_img v) +{ + v2f_img o; + o.pos = v.vertex * float4(2, 2, 0, 0) + float4(0, 0, 0, 1); +#if UNITY_UV_STARTS_AT_TOP + o.uv = v.texcoord * float2(1, -1) + float2(0, 1); +#else + o.uv = v.texcoord; +#endif + return o; +} + +#if !SHADER_API_GLES // excluding the MRT pass under GLES2 + +struct CombinerOutput +{ + half4 gbuffer0 : SV_Target0; + half4 gbuffer3 : SV_Target1; +}; + +CombinerOutput frag_gbuffer_combine(v2f_img i) +{ + half ao = tex2D(_OcclusionTexture, i.uv).r; + CombinerOutput o; + o.gbuffer0 = half4(0, 0, 0, ao); + o.gbuffer3 = half4((half3)EncodeAO(ao), 0); + return o; +} + +#else + +fixed4 frag_gbuffer_combine(v2f_img i) : SV_Target0 +{ + return 0; +} + +#endif + +// Debug blit +half4 frag_blit_ao(v2f_multitex i) : SV_Target +{ + half4 src = tex2D(_MainTex, i.uv0); + half ao = tex2D(_OcclusionTexture, i.uv1).r; + return half4(CombineOcclusion(1, ao), src.a); +} diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/AmbientOcclusion/Resources/AmbientOcclusion.cginc.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/AmbientOcclusion/Resources/AmbientOcclusion.cginc.meta new file mode 100644 index 0000000..81f16c6 --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/AmbientOcclusion/Resources/AmbientOcclusion.cginc.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 7bbc8f354c22e447dbd9deb502530d91 +timeCreated: 1463553768 +licenseType: Store +ShaderImporter: + defaultTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/AmbientOcclusion/Resources/AmbientOcclusion.shader b/IronToad_UnityProject/Assets/Standard Assets/Effects/AmbientOcclusion/Resources/AmbientOcclusion.shader new file mode 100644 index 0000000..bd330a2 --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/AmbientOcclusion/Resources/AmbientOcclusion.shader @@ -0,0 +1,129 @@ +Shader "Hidden/Image Effects/Cinematic/AmbientOcclusion" +{ + Properties + { + _MainTex("", 2D) = ""{} + _OcclusionTexture("", 2D) = ""{} + } + SubShader + { + // 0: Occlusion estimation with CameraDepthTexture + Pass + { + ZTest Always Cull Off ZWrite Off + CGPROGRAM + #define SOURCE_DEPTH 1 + #include "AmbientOcclusion.cginc" + #pragma vertex vert_img + #pragma fragment frag_ao + #pragma target 3.0 + ENDCG + } + // 1: Occlusion estimation with CameraDepthNormalsTexture + Pass + { + ZTest Always Cull Off ZWrite Off + CGPROGRAM + #define SOURCE_DEPTHNORMALS 1 + #include "AmbientOcclusion.cginc" + #pragma vertex vert_img + #pragma fragment frag_ao + #pragma target 3.0 + ENDCG + } + // 2: Occlusion estimation with G-Buffer + Pass + { + ZTest Always Cull Off ZWrite Off + CGPROGRAM + #define SOURCE_GBUFFER 1 + #include "AmbientOcclusion.cginc" + #pragma vertex vert_img + #pragma fragment frag_ao + #pragma target 3.0 + ENDCG + } + // 3: Noise reduction (first pass) with CameraDepthNormalsTexture + Pass + { + ZTest Always Cull Off ZWrite Off + CGPROGRAM + #define SOURCE_DEPTHNORMALS 1 + #include "AmbientOcclusion.cginc" + #pragma vertex vert_img + #pragma fragment frag_blur1 + #pragma target 3.0 + ENDCG + } + // 4: Noise reduction (first pass) with G Buffer + Pass + { + ZTest Always Cull Off ZWrite Off + CGPROGRAM + #define SOURCE_GBUFFER 1 + #include "AmbientOcclusion.cginc" + #pragma vertex vert_img + #pragma fragment frag_blur1 + #pragma target 3.0 + ENDCG + } + // 5: Noise reduction (second pass) with CameraDepthNormalsTexture + Pass + { + ZTest Always Cull Off ZWrite Off + CGPROGRAM + #define SOURCE_DEPTHNORMALS 1 + #include "AmbientOcclusion.cginc" + #pragma vertex vert_img + #pragma fragment frag_blur2 + #pragma target 3.0 + ENDCG + } + // 6: Noise reduction (second pass) with G Buffer + Pass + { + ZTest Always Cull Off ZWrite Off + CGPROGRAM + #define SOURCE_GBUFFER 1 + #include "AmbientOcclusion.cginc" + #pragma vertex vert_img + #pragma fragment frag_blur2 + #pragma target 3.0 + ENDCG + } + // 7: Occlusion combiner + Pass + { + ZTest Always Cull Off ZWrite Off + CGPROGRAM + #include "AmbientOcclusion.cginc" + #pragma vertex vert_multitex + #pragma fragment frag_combine + #pragma target 3.0 + ENDCG + } + // 8: Occlusion combiner for the ambient-only mode + Pass + { + Blend Zero OneMinusSrcColor, Zero OneMinusSrcAlpha + ZTest Always Cull Off ZWrite Off + CGPROGRAM + #include "AmbientOcclusion.cginc" + #pragma vertex vert_gbuffer + #pragma fragment frag_gbuffer_combine + #pragma target 3.0 + ENDCG + } + // 9: Debug blit + Pass + { + ZTest Always Cull Off ZWrite Off + CGPROGRAM + #include "AmbientOcclusion.cginc" + #pragma vertex vert_multitex + #pragma fragment frag_blit_ao + #pragma target 3.0 + ENDCG + } + } +} diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/AmbientOcclusion/Resources/AmbientOcclusion.shader.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/AmbientOcclusion/Resources/AmbientOcclusion.shader.meta new file mode 100644 index 0000000..f4022b7 --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/AmbientOcclusion/Resources/AmbientOcclusion.shader.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 65e203e5acda447acbf9dc1ef78c4a39 +timeCreated: 1457327141 +licenseType: Store +ShaderImporter: + defaultTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing.meta new file mode 100644 index 0000000..1139bce --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 4b15f777774297b4f91455d3353a0c40 +folderAsset: yes +timeCreated: 1454589502 +licenseType: Store +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/AntiAliasing.cs b/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/AntiAliasing.cs new file mode 100644 index 0000000..71c093c --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/AntiAliasing.cs @@ -0,0 +1,90 @@ +using UnityEngine; + +namespace UnityStandardAssets.CinematicEffects +{ + [ExecuteInEditMode] + [RequireComponent(typeof(Camera))] + [AddComponentMenu("Image Effects/Anti-aliasing")] +#if UNITY_5_4_OR_NEWER + [ImageEffectAllowedInSceneView] +#endif + public class AntiAliasing : MonoBehaviour + { + public enum Method + { + Smaa, + Fxaa + } + + [SerializeField] + private SMAA m_SMAA = new SMAA(); + + [SerializeField] + private FXAA m_FXAA = new FXAA(); + + [SerializeField, HideInInspector] + private int m_Method = (int)Method.Smaa; + public int method + { + get { return m_Method; } + + set + { + if (m_Method == value) + return; + + m_Method = value; + } + } + + public IAntiAliasing current + { + get + { + if (method == (int)Method.Smaa) + return m_SMAA; + else + return m_FXAA; + } + } + + private Camera m_Camera; + public Camera cameraComponent + { + get + { + if (m_Camera == null) + m_Camera = GetComponent(); + + return m_Camera; + } + } + + private void OnEnable() + { + m_SMAA.OnEnable(this); + m_FXAA.OnEnable(this); + } + + private void OnDisable() + { + m_SMAA.OnDisable(); + m_FXAA.OnDisable(); + } + + private void OnPreCull() + { + current.OnPreCull(cameraComponent); + } + + private void OnPostRender() + { + current.OnPostRender(cameraComponent); + } + + private void OnRenderImage(RenderTexture source, RenderTexture destination) + { + current.OnRenderImage(cameraComponent, source, destination); + } + } +} diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/AntiAliasing.cs.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/AntiAliasing.cs.meta new file mode 100644 index 0000000..ad964f3 --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/AntiAliasing.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: fdc35e0180670ab4e8d2f9439137791f +timeCreated: 1454589503 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/Editor.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/Editor.meta new file mode 100644 index 0000000..e6a1c7a --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/Editor.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 738f82ccf57b5974cb672f8032c72169 +folderAsset: yes +timeCreated: 1454595975 +licenseType: Store +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/Editor/AntiAliasingEditor.cs b/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/Editor/AntiAliasingEditor.cs new file mode 100644 index 0000000..aafe0e3 --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/Editor/AntiAliasingEditor.cs @@ -0,0 +1,64 @@ +using System; +using UnityEditor; + +namespace UnityStandardAssets.CinematicEffects +{ + [CustomEditor(typeof(AntiAliasing))] + public class AntiAliasingEditor : Editor + { + private string[] methodNames = + { + "Subpixel Morphological Anti-aliasing", + "Fast Approximate Anti-aliasing" + }; + + private int m_SelectedMethod; + + private SMAAEditor m_SMAAEditor = new SMAAEditor(); + private FXAAEditor m_FXAAEditor = new FXAAEditor(); + + IAntiAliasingEditor m_AntiAliasingEditor; + + private void OnEnable() + { + m_SMAAEditor.OnEnable(serializedObject, "m_SMAA"); + m_FXAAEditor.OnEnable(serializedObject, "m_FXAA"); + } + + public override void OnInspectorGUI() + { + var antiAliasingTarget = (AntiAliasing)target; + + m_SelectedMethod = antiAliasingTarget.method; + + EditorGUI.BeginChangeCheck(); + m_SelectedMethod = EditorGUILayout.Popup("Method", m_SelectedMethod, methodNames); + + bool dirty = false; + + if (EditorGUI.EndChangeCheck()) + { + if (m_SelectedMethod < 0) + m_SelectedMethod = 0; + else if (m_SelectedMethod > 1) + m_SelectedMethod = 1; + + antiAliasingTarget.method = m_SelectedMethod; + dirty = true; + } + + if (m_SelectedMethod == 0) + m_AntiAliasingEditor = m_SMAAEditor; + else + m_AntiAliasingEditor = m_FXAAEditor; + + dirty |= m_AntiAliasingEditor.OnInspectorGUI(antiAliasingTarget.current); + + if (dirty) + { + EditorUtility.SetDirty(antiAliasingTarget); + serializedObject.ApplyModifiedProperties(); + } + } + } +} diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/Editor/AntiAliasingEditor.cs.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/Editor/AntiAliasingEditor.cs.meta new file mode 100644 index 0000000..1b65d6f --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/Editor/AntiAliasingEditor.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 6bd9375ab74a65448b556b0452e8c6af +timeCreated: 1454593885 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/Editor/IAntiAliasingEditor.cs b/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/Editor/IAntiAliasingEditor.cs new file mode 100644 index 0000000..fbc262b --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/Editor/IAntiAliasingEditor.cs @@ -0,0 +1,10 @@ +using UnityEditor; + +namespace UnityStandardAssets.CinematicEffects +{ + public interface IAntiAliasingEditor + { + void OnEnable(SerializedObject serializedObject, string path); + bool OnInspectorGUI(IAntiAliasing target); + } +} diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/Editor/IAntiAliasingEditor.cs.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/Editor/IAntiAliasingEditor.cs.meta new file mode 100644 index 0000000..e3af631 --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/Editor/IAntiAliasingEditor.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 015ee83e537e9e4438f403e2149c69ae +timeCreated: 1454595240 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/FXAA.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/FXAA.meta new file mode 100644 index 0000000..51a1389 --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/FXAA.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 7629f5693f26f34448aa9c713d257e26 +folderAsset: yes +timeCreated: 1453733554 +licenseType: Store +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/FXAA/Editor.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/FXAA/Editor.meta new file mode 100644 index 0000000..64e44f1 --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/FXAA/Editor.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 880813d23951c624d9d5c3e6d2a4e93c +folderAsset: yes +timeCreated: 1454331861 +licenseType: Store +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/FXAA/Editor/FXAAEditor.cs b/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/FXAA/Editor/FXAAEditor.cs new file mode 100644 index 0000000..cfeb868 --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/FXAA/Editor/FXAAEditor.cs @@ -0,0 +1,57 @@ +using UnityEditor; + +namespace UnityStandardAssets.CinematicEffects +{ + public class FXAAEditor : IAntiAliasingEditor + { + private string[] presetNames = + { + "Extreme performance", + "Performance", + "Default", + "Quality", + "Extreme quality" + }; + + + public void OnEnable(SerializedObject serializedObject, string path) + { + } + + public bool OnInspectorGUI(IAntiAliasing target) + { + var fxaaTarget = (FXAA)target; + + if (!fxaaTarget.validSourceFormat) + EditorGUILayout.HelpBox("FXAA should be used at the end of the post-processing stack after conversion to LDR (after Tonemapping) to maximize quality and avoid artifacts.", MessageType.Warning); + + int selectedPreset = 2; + + if (fxaaTarget.preset.Equals(FXAA.Preset.extremePerformancePreset)) + selectedPreset = 0; + else if (fxaaTarget.preset.Equals(FXAA.Preset.performancePreset)) + selectedPreset = 1; + else if (fxaaTarget.preset.Equals(FXAA.Preset.defaultPreset)) + selectedPreset = 2; + else if (fxaaTarget.preset.Equals(FXAA.Preset.qualityPreset)) + selectedPreset = 3; + else if (fxaaTarget.preset.Equals(FXAA.Preset.extremeQualityPreset)) + selectedPreset = 4; + + EditorGUI.BeginChangeCheck(); + selectedPreset = EditorGUILayout.Popup("Preset", selectedPreset, presetNames); + + if (EditorGUI.EndChangeCheck()) + { + if (selectedPreset < 0) + selectedPreset = 0; + else if (selectedPreset > 4) + selectedPreset = 4; + + fxaaTarget.preset = FXAA.availablePresets[selectedPreset]; + return true; + } + return false; + } + } +} diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/FXAA/Editor/FXAAEditor.cs.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/FXAA/Editor/FXAAEditor.cs.meta new file mode 100644 index 0000000..26b7b2a --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/FXAA/Editor/FXAAEditor.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 60bfb637c85e3e04ea76962349fee327 +timeCreated: 1454331861 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/FXAA/FXAA.cs b/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/FXAA/FXAA.cs new file mode 100644 index 0000000..8e5a29c --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/FXAA/FXAA.cs @@ -0,0 +1,255 @@ +using UnityEngine; +using System; + +using Object = UnityEngine.Object; + +namespace UnityStandardAssets.CinematicEffects +{ + [Serializable] + public class FXAA : IAntiAliasing + { + private Shader m_Shader; + private Shader shader + { + get + { + if (m_Shader == null) + m_Shader = Shader.Find("Hidden/Fast Approximate Anti-aliasing"); + + return m_Shader; + } + } + + private Material m_Material; + public Material material + { + get + { + if (m_Material == null) + m_Material = ImageEffectHelper.CheckShaderAndCreateMaterial(shader); + + return m_Material; + } + } + + [Serializable] + public struct QualitySettings + { + [Tooltip("The amount of desired sub-pixel aliasing removal. Effects the sharpeness of the output.")] + [Range(0.0f, 1.0f)] + public float subpixelAliasingRemovalAmount; + + [Tooltip("The minimum amount of local contrast required to qualify a region as containing an edge.")] + [Range(0.063f, 0.333f)] + public float edgeDetectionThreshold; + + [Tooltip("Local contrast adaptation value to disallow the algorithm from executing on the darker regions.")] + [Range(0.0f, 0.0833f)] + public float minimumRequiredLuminance; + } + + [Serializable] + public struct ConsoleSettings + { + [Tooltip("The amount of spread applied to the sampling coordinates while sampling for subpixel information.")] + [Range(0.33f, 0.5f)] + public float subpixelSpreadAmount; + + [Tooltip("This value dictates how sharp the edges in the image are kept; a higher value implies sharper edges.")] + [Range(2.0f, 8.0f)] + public float edgeSharpnessAmount; + + [Tooltip("The minimum amount of local contrast required to qualify a region as containing an edge.")] + [Range(0.125f, 0.25f)] + public float edgeDetectionThreshold; + + [Tooltip("Local contrast adaptation value to disallow the algorithm from executing on the darker regions.")] + [Range(0.04f, 0.06f)] + public float minimumRequiredLuminance; + } + + [Serializable] + public struct Preset + { + [AttributeUsage(AttributeTargets.Field)] + public class LayoutAttribute : PropertyAttribute + {} + + [Layout] + public QualitySettings qualitySettings; + + [Layout] + public ConsoleSettings consoleSettings; + + private static readonly Preset s_ExtremePerformance = new Preset + { + qualitySettings = new QualitySettings + { + subpixelAliasingRemovalAmount = 0.0f, + edgeDetectionThreshold = 0.333f, + minimumRequiredLuminance = 0.0833f + }, + + consoleSettings = new ConsoleSettings + { + subpixelSpreadAmount = 0.33f, + edgeSharpnessAmount = 8.0f, + edgeDetectionThreshold = 0.25f, + minimumRequiredLuminance = 0.06f + } + }; + + private static readonly Preset s_Performance = new Preset + { + qualitySettings = new QualitySettings + { + subpixelAliasingRemovalAmount = 0.25f, + edgeDetectionThreshold = 0.25f, + minimumRequiredLuminance = 0.0833f + }, + + consoleSettings = new ConsoleSettings + { + subpixelSpreadAmount = 0.33f, + edgeSharpnessAmount = 8.0f, + edgeDetectionThreshold = 0.125f, + minimumRequiredLuminance = 0.06f + } + }; + + private static readonly Preset s_Default = new Preset + { + qualitySettings = new QualitySettings + { + subpixelAliasingRemovalAmount = 0.75f, + edgeDetectionThreshold = 0.166f, + minimumRequiredLuminance = 0.0833f + }, + + consoleSettings = new ConsoleSettings + { + subpixelSpreadAmount = 0.5f, + edgeSharpnessAmount = 8.0f, + edgeDetectionThreshold = 0.125f, + minimumRequiredLuminance = 0.05f + } + }; + + private static readonly Preset s_Quality = new Preset + { + qualitySettings = new QualitySettings + { + subpixelAliasingRemovalAmount = 1.0f, + edgeDetectionThreshold = 0.125f, + minimumRequiredLuminance = 0.0625f + }, + + consoleSettings = new ConsoleSettings + { + subpixelSpreadAmount = 0.5f, + edgeSharpnessAmount = 4.0f, + edgeDetectionThreshold = 0.125f, + minimumRequiredLuminance = 0.04f + } + }; + + private static readonly Preset s_ExtremeQuality = new Preset + { + qualitySettings = new QualitySettings + { + subpixelAliasingRemovalAmount = 1.0f, + edgeDetectionThreshold = 0.063f, + minimumRequiredLuminance = 0.0312f + }, + + consoleSettings = new ConsoleSettings + { + subpixelSpreadAmount = 0.5f, + edgeSharpnessAmount = 2.0f, + edgeDetectionThreshold = 0.125f, + minimumRequiredLuminance = 0.04f + } + }; + + public static Preset extremePerformancePreset + { + get { return s_ExtremePerformance; } + } + + public static Preset performancePreset + { + get { return s_Performance; } + } + + public static Preset defaultPreset + { + get { return s_Default; } + } + + public static Preset qualityPreset + { + get { return s_Quality; } + } + + public static Preset extremeQualityPreset + { + get { return s_ExtremeQuality; } + } + } + + [SerializeField, HideInInspector] + public Preset preset = Preset.defaultPreset; + + public static Preset[] availablePresets = + { + Preset.extremePerformancePreset, + Preset.performancePreset, + Preset.defaultPreset, + Preset.qualityPreset, + Preset.extremeQualityPreset + }; + + public bool validSourceFormat { get; private set; } + + public void OnEnable(AntiAliasing owner) + { + if (!ImageEffectHelper.IsSupported(shader, true, false, owner)) + owner.enabled = false; + } + + public void OnDisable() + { + if (m_Material != null) + Object.DestroyImmediate(m_Material); + } + + public void OnPreCull(Camera camera) + { + } + + public void OnPostRender(Camera camera) + { + } + + public void OnRenderImage(Camera camera, RenderTexture source, RenderTexture destination) + { +#if UNITY_EDITOR + validSourceFormat = true; + + if (source.format == RenderTextureFormat.ARGBHalf + || source.format == RenderTextureFormat.ARGBFloat + || source.format == RenderTextureFormat.ARGB2101010) + validSourceFormat = false; +#endif + + material.SetVector("_QualitySettings", new Vector3(preset.qualitySettings.subpixelAliasingRemovalAmount, + preset.qualitySettings.edgeDetectionThreshold, preset.qualitySettings.minimumRequiredLuminance)); + + material.SetVector("_ConsoleSettings", new Vector4(preset.consoleSettings.subpixelSpreadAmount, + preset.consoleSettings.edgeSharpnessAmount, preset.consoleSettings.edgeDetectionThreshold, + preset.consoleSettings.minimumRequiredLuminance)); + + Graphics.Blit(source, destination, material, 0); + } + } +} diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/FXAA/FXAA.cs.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/FXAA/FXAA.cs.meta new file mode 100644 index 0000000..e9f0eab --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/FXAA/FXAA.cs.meta @@ -0,0 +1,13 @@ +fileFormatVersion: 2 +guid: 8ca0fe85db4ef594fb0771b250c00e23 +timeCreated: 1453738651 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: + - shader: {fileID: 4800000, guid: 3eaaee164ee0fed4d9a0bbe8434805a6, type: 3} + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/FXAA/Resources.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/FXAA/Resources.meta new file mode 100644 index 0000000..fb2603e --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/FXAA/Resources.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 3f7cc4a9005f5f846957997471c28f2b +folderAsset: yes +timeCreated: 1455022968 +licenseType: Store +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/FXAA/Resources/FXAA.shader b/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/FXAA/Resources/FXAA.shader new file mode 100644 index 0000000..69a1ba3 --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/FXAA/Resources/FXAA.shader @@ -0,0 +1,104 @@ +Shader "Hidden/Fast Approximate Anti-aliasing" +{ + Properties + { + _MainTex ("Texture", 2D) = "white" {} + } + + CGINCLUDE + #pragma fragmentoption ARB_precision_hint_fastest + + #if defined(SHADER_API_PS3) + #define FXAA_PS3 1 + + // Shaves off 2 cycles from the shader + #define FXAA_EARLY_EXIT 0 + #elif defined(SHADER_API_XBOX360) + #define FXAA_360 1 + + // Shaves off 10ms from the shader's execution time + #define FXAA_EARLY_EXIT 1 + #else + #define FXAA_PC 1 + #endif + + #define FXAA_HLSL_3 1 + #define FXAA_QUALITY__PRESET 39 + + #define FXAA_GREEN_AS_LUMA 1 + + #pragma target 3.0 + #include "FXAA3.cginc" + + float4 _MainTex_TexelSize; + + float3 _QualitySettings; + float4 _ConsoleSettings; + + struct Input + { + float4 position : POSITION; + float2 uv : TEXCOORD0; + }; + + struct Varying + { + float4 position : SV_POSITION; + float2 uv : TEXCOORD0; + }; + + Varying vertex(Input input) + { + Varying output; + + output.position = mul(UNITY_MATRIX_MVP, input.position); + output.uv = input.uv; + + return output; + } + + sampler2D _MainTex; + + float calculateLuma(float4 color) + { + return color.g * 1.963211 + color.r; + } + + fixed4 fragment(Varying input) : SV_Target + { + const float4 consoleUV = input.uv.xyxy + .5 * float4(-_MainTex_TexelSize.xy, _MainTex_TexelSize.xy); + const float4 consoleSubpixelFrame = _ConsoleSettings.x * float4(-1., -1., 1., 1.) * + _MainTex_TexelSize.xyxy; + + const float4 consoleSubpixelFramePS3 = float4(-2., -2., 2., 2.) * _MainTex_TexelSize.xyxy; + const float4 consoleSubpixelFrameXBOX = float4(8., 8., -4., -4.) * _MainTex_TexelSize.xyxy; + + #if defined(SHADER_API_XBOX360) + const float4 consoleConstants = float4(1., -1., .25, -.25); + #else + const float4 consoleConstants = float4(0., 0., 0., 0.); + #endif + + return FxaaPixelShader(input.uv, consoleUV, _MainTex, _MainTex, _MainTex, _MainTex_TexelSize.xy, + consoleSubpixelFrame, consoleSubpixelFramePS3, consoleSubpixelFrameXBOX, + _QualitySettings.x, _QualitySettings.y, _QualitySettings.z, _ConsoleSettings.y, _ConsoleSettings.z, + _ConsoleSettings.w, consoleConstants); + } + ENDCG + + SubShader + { + ZTest Always Cull Off ZWrite Off + Fog { Mode off } + + Pass + { + CGPROGRAM + #pragma vertex vertex + #pragma fragment fragment + + #include "UnityCG.cginc" + ENDCG + } + } +} diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/FXAA/Resources/FXAA.shader.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/FXAA/Resources/FXAA.shader.meta new file mode 100644 index 0000000..e1523d1 --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/FXAA/Resources/FXAA.shader.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 3eaaee164ee0fed4d9a0bbe8434805a6 +timeCreated: 1453736553 +licenseType: Store +ShaderImporter: + defaultTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/FXAA/Resources/FXAA3.cginc b/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/FXAA/Resources/FXAA3.cginc new file mode 100644 index 0000000..d5ee34b --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/FXAA/Resources/FXAA3.cginc @@ -0,0 +1,2047 @@ +/*============================================================================ + + + NVIDIA FXAA 3.11 by TIMOTHY LOTTES + + +------------------------------------------------------------------------------ +COPYRIGHT (C) 2010, 2011 NVIDIA CORPORATION. ALL RIGHTS RESERVED. +------------------------------------------------------------------------------ +TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, THIS SOFTWARE IS PROVIDED +*AS IS* AND NVIDIA AND ITS SUPPLIERS DISCLAIM ALL WARRANTIES, EITHER EXPRESS +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL NVIDIA +OR ITS SUPPLIERS BE LIABLE FOR ANY SPECIAL, INCIDENTAL, INDIRECT, OR +CONSEQUENTIAL DAMAGES WHATSOEVER (INCLUDING, WITHOUT LIMITATION, DAMAGES FOR +LOSS OF BUSINESS PROFITS, BUSINESS INTERRUPTION, LOSS OF BUSINESS INFORMATION, +OR ANY OTHER PECUNIARY LOSS) ARISING OUT OF THE USE OF OR INABILITY TO USE +THIS SOFTWARE, EVEN IF NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + +------------------------------------------------------------------------------ + INTEGRATION CHECKLIST +------------------------------------------------------------------------------ +(1.) +In the shader source, setup defines for the desired configuration. +When providing multiple shaders (for different presets), +simply setup the defines differently in multiple files. +Example, + + #define FXAA_PC 1 + #define FXAA_HLSL_5 1 + #define FXAA_QUALITY__PRESET 12 + +Or, + + #define FXAA_360 1 + +Or, + + #define FXAA_PS3 1 + +Etc. + +(2.) +Then include this file, + + #include "Fxaa3_11.h" + +(3.) +Then call the FXAA pixel shader from within your desired shader. +Look at the FXAA Quality FxaaPixelShader() for docs on inputs. +As for FXAA 3.11 all inputs for all shaders are the same +to enable easy porting between platforms. + + return FxaaPixelShader(...); + +(4.) +Insure pass prior to FXAA outputs RGBL (see next section). +Or use, + + #define FXAA_GREEN_AS_LUMA 1 + +(5.) +Setup engine to provide the following constants +which are used in the FxaaPixelShader() inputs, + + FxaaFloat2 fxaaQualityRcpFrame, + FxaaFloat4 fxaaConsoleRcpFrameOpt, + FxaaFloat4 fxaaConsoleRcpFrameOpt2, + FxaaFloat4 fxaaConsole360RcpFrameOpt2, + FxaaFloat fxaaQualitySubpix, + FxaaFloat fxaaQualityEdgeThreshold, + FxaaFloat fxaaQualityEdgeThresholdMin, + FxaaFloat fxaaConsoleEdgeSharpness, + FxaaFloat fxaaConsoleEdgeThreshold, + FxaaFloat fxaaConsoleEdgeThresholdMin, + FxaaFloat4 fxaaConsole360ConstDir + +Look at the FXAA Quality FxaaPixelShader() for docs on inputs. + +(6.) +Have FXAA vertex shader run as a full screen triangle, +and output "pos" and "fxaaConsolePosPos" +such that inputs in the pixel shader provide, + + // {xy} = center of pixel + FxaaFloat2 pos, + + // {xy__} = upper left of pixel + // {__zw} = lower right of pixel + FxaaFloat4 fxaaConsolePosPos, + +(7.) +Insure the texture sampler(s) used by FXAA are set to bilinear filtering. + + +------------------------------------------------------------------------------ + INTEGRATION - RGBL AND COLORSPACE +------------------------------------------------------------------------------ +FXAA3 requires RGBL as input unless the following is set, + + #define FXAA_GREEN_AS_LUMA 1 + +In which case the engine uses green in place of luma, +and requires RGB input is in a non-linear colorspace. + +RGB should be LDR (low dynamic range). +Specifically do FXAA after tonemapping. + +RGB data as returned by a texture fetch can be non-linear, +or linear when FXAA_GREEN_AS_LUMA is not set. +Note an "sRGB format" texture counts as linear, +because the result of a texture fetch is linear data. +Regular "RGBA8" textures in the sRGB colorspace are non-linear. + +If FXAA_GREEN_AS_LUMA is not set, +luma must be stored in the alpha channel prior to running FXAA. +This luma should be in a perceptual space (could be gamma 2.0). +Example pass before FXAA where output is gamma 2.0 encoded, + + color.rgb = ToneMap(color.rgb); // linear color output + color.rgb = sqrt(color.rgb); // gamma 2.0 color output + return color; + +To use FXAA, + + color.rgb = ToneMap(color.rgb); // linear color output + color.rgb = sqrt(color.rgb); // gamma 2.0 color output + color.a = dot(color.rgb, FxaaFloat3(0.299, 0.587, 0.114)); // compute luma + return color; + +Another example where output is linear encoded, +say for instance writing to an sRGB formated render target, +where the render target does the conversion back to sRGB after blending, + + color.rgb = ToneMap(color.rgb); // linear color output + return color; + +To use FXAA, + + color.rgb = ToneMap(color.rgb); // linear color output + color.a = sqrt(dot(color.rgb, FxaaFloat3(0.299, 0.587, 0.114))); // compute luma + return color; + +Getting luma correct is required for the algorithm to work correctly. + + +------------------------------------------------------------------------------ + BEING LINEARLY CORRECT? +------------------------------------------------------------------------------ +Applying FXAA to a framebuffer with linear RGB color will look worse. +This is very counter intuitive, but happends to be true in this case. +The reason is because dithering artifacts will be more visiable +in a linear colorspace. + + +------------------------------------------------------------------------------ + COMPLEX INTEGRATION +------------------------------------------------------------------------------ +Q. What if the engine is blending into RGB before wanting to run FXAA? + +A. In the last opaque pass prior to FXAA, + have the pass write out luma into alpha. + Then blend into RGB only. + FXAA should be able to run ok + assuming the blending pass did not any add aliasing. + This should be the common case for particles and common blending passes. + +A. Or use FXAA_GREEN_AS_LUMA. + +============================================================================*/ + +/*============================================================================ + + INTEGRATION KNOBS + +============================================================================*/ +// +// FXAA_PS3 and FXAA_360 choose the console algorithm (FXAA3 CONSOLE). +// FXAA_360_OPT is a prototype for the new optimized 360 version. +// +// 1 = Use API. +// 0 = Don't use API. +// +/*--------------------------------------------------------------------------*/ +#ifndef FXAA_PS3 + #define FXAA_PS3 0 +#endif +/*--------------------------------------------------------------------------*/ +#ifndef FXAA_360 + #define FXAA_360 0 +#endif +/*--------------------------------------------------------------------------*/ +#ifndef FXAA_360_OPT + #define FXAA_360_OPT 0 +#endif +/*==========================================================================*/ +#ifndef FXAA_PC + // + // FXAA Quality + // The high quality PC algorithm. + // + #define FXAA_PC 0 +#endif +/*--------------------------------------------------------------------------*/ +#ifndef FXAA_PC_CONSOLE + // + // The console algorithm for PC is included + // for developers targeting really low spec machines. + // Likely better to just run FXAA_PC, and use a really low preset. + // + #define FXAA_PC_CONSOLE 0 +#endif +/*--------------------------------------------------------------------------*/ +#ifndef FXAA_GLSL_120 + #define FXAA_GLSL_120 0 +#endif +/*--------------------------------------------------------------------------*/ +#ifndef FXAA_GLSL_130 + #define FXAA_GLSL_130 0 +#endif +/*--------------------------------------------------------------------------*/ +#ifndef FXAA_HLSL_3 + #define FXAA_HLSL_3 0 +#endif +/*--------------------------------------------------------------------------*/ +#ifndef FXAA_HLSL_4 + #define FXAA_HLSL_4 0 +#endif +/*--------------------------------------------------------------------------*/ +#ifndef FXAA_HLSL_5 + #define FXAA_HLSL_5 0 +#endif +/*==========================================================================*/ +#ifndef FXAA_GREEN_AS_LUMA + // + // For those using non-linear color, + // and either not able to get luma in alpha, or not wanting to, + // this enables FXAA to run using green as a proxy for luma. + // So with this enabled, no need to pack luma in alpha. + // + // This will turn off AA on anything which lacks some amount of green. + // Pure red and blue or combination of only R and B, will get no AA. + // + // Might want to lower the settings for both, + // fxaaConsoleEdgeThresholdMin + // fxaaQualityEdgeThresholdMin + // In order to insure AA does not get turned off on colors + // which contain a minor amount of green. + // + // 1 = On. + // 0 = Off. + // + #define FXAA_GREEN_AS_LUMA 0 +#endif +/*--------------------------------------------------------------------------*/ +#ifndef FXAA_EARLY_EXIT + // + // Controls algorithm's early exit path. + // On PS3 turning this ON adds 2 cycles to the shader. + // On 360 turning this OFF adds 10ths of a millisecond to the shader. + // Turning this off on console will result in a more blurry image. + // So this defaults to on. + // + // 1 = On. + // 0 = Off. + // + #define FXAA_EARLY_EXIT 1 +#endif +/*--------------------------------------------------------------------------*/ +#ifndef FXAA_DISCARD + // + // Only valid for PC OpenGL currently. + // Probably will not work when FXAA_GREEN_AS_LUMA = 1. + // + // 1 = Use discard on pixels which don't need AA. + // For APIs which enable concurrent TEX+ROP from same surface. + // 0 = Return unchanged color on pixels which don't need AA. + // + #define FXAA_DISCARD 0 +#endif +/*--------------------------------------------------------------------------*/ +#ifndef FXAA_FAST_PIXEL_OFFSET + // + // Used for GLSL 120 only. + // + // 1 = GL API supports fast pixel offsets + // 0 = do not use fast pixel offsets + // + #ifdef GL_EXT_gpu_shader4 + #define FXAA_FAST_PIXEL_OFFSET 1 + #endif + #ifdef GL_NV_gpu_shader5 + #define FXAA_FAST_PIXEL_OFFSET 1 + #endif + #ifdef GL_ARB_gpu_shader5 + #define FXAA_FAST_PIXEL_OFFSET 1 + #endif + #ifndef FXAA_FAST_PIXEL_OFFSET + #define FXAA_FAST_PIXEL_OFFSET 0 + #endif +#endif +/*--------------------------------------------------------------------------*/ +#ifndef FXAA_GATHER4_ALPHA + // + // 1 = API supports gather4 on alpha channel. + // 0 = API does not support gather4 on alpha channel. + // + #if (FXAA_HLSL_5 == 1) + #define FXAA_GATHER4_ALPHA 1 + #endif + #ifdef GL_ARB_gpu_shader5 + #define FXAA_GATHER4_ALPHA 1 + #endif + #ifdef GL_NV_gpu_shader5 + #define FXAA_GATHER4_ALPHA 1 + #endif + #ifndef FXAA_GATHER4_ALPHA + #define FXAA_GATHER4_ALPHA 0 + #endif +#endif + +/*============================================================================ + FXAA CONSOLE PS3 - TUNING KNOBS +============================================================================*/ +#ifndef FXAA_CONSOLE__PS3_EDGE_SHARPNESS + // + // Consoles the sharpness of edges on PS3 only. + // Non-PS3 tuning is done with shader input. + // + // Due to the PS3 being ALU bound, + // there are only two safe values here: 4 and 8. + // These options use the shaders ability to a free *|/ by 2|4|8. + // + // 8.0 is sharper + // 4.0 is softer + // 2.0 is really soft (good for vector graphics inputs) + // + #if 1 + #define FXAA_CONSOLE__PS3_EDGE_SHARPNESS 8.0 + #endif + #if 0 + #define FXAA_CONSOLE__PS3_EDGE_SHARPNESS 4.0 + #endif + #if 0 + #define FXAA_CONSOLE__PS3_EDGE_SHARPNESS 2.0 + #endif +#endif +/*--------------------------------------------------------------------------*/ +#ifndef FXAA_CONSOLE__PS3_EDGE_THRESHOLD + // + // Only effects PS3. + // Non-PS3 tuning is done with shader input. + // + // The minimum amount of local contrast required to apply algorithm. + // The console setting has a different mapping than the quality setting. + // + // This only applies when FXAA_EARLY_EXIT is 1. + // + // Due to the PS3 being ALU bound, + // there are only two safe values here: 0.25 and 0.125. + // These options use the shaders ability to a free *|/ by 2|4|8. + // + // 0.125 leaves less aliasing, but is softer + // 0.25 leaves more aliasing, and is sharper + // + #if 1 + #define FXAA_CONSOLE__PS3_EDGE_THRESHOLD 0.125 + #else + #define FXAA_CONSOLE__PS3_EDGE_THRESHOLD 0.25 + #endif +#endif + +/*============================================================================ + FXAA QUALITY - TUNING KNOBS +------------------------------------------------------------------------------ +NOTE the other tuning knobs are now in the shader function inputs! +============================================================================*/ +#ifndef FXAA_QUALITY__PRESET + // + // Choose the quality preset. + // This needs to be compiled into the shader as it effects code. + // Best option to include multiple presets is to + // in each shader define the preset, then include this file. + // + // OPTIONS + // ----------------------------------------------------------------------- + // 10 to 15 - default medium dither (10=fastest, 15=highest quality) + // 20 to 29 - less dither, more expensive (20=fastest, 29=highest quality) + // 39 - no dither, very expensive + // + // NOTES + // ----------------------------------------------------------------------- + // 12 = slightly faster then FXAA 3.9 and higher edge quality (default) + // 13 = about same speed as FXAA 3.9 and better than 12 + // 23 = closest to FXAA 3.9 visually and performance wise + // _ = the lowest digit is directly related to performance + // _ = the highest digit is directly related to style + // + #define FXAA_QUALITY__PRESET 12 +#endif + + +/*============================================================================ + + FXAA QUALITY - PRESETS + +============================================================================*/ + +/*============================================================================ + FXAA QUALITY - MEDIUM DITHER PRESETS +============================================================================*/ +#if (FXAA_QUALITY__PRESET == 10) + #define FXAA_QUALITY__PS 3 + #define FXAA_QUALITY__P0 1.5 + #define FXAA_QUALITY__P1 3.0 + #define FXAA_QUALITY__P2 12.0 +#endif +/*--------------------------------------------------------------------------*/ +#if (FXAA_QUALITY__PRESET == 11) + #define FXAA_QUALITY__PS 4 + #define FXAA_QUALITY__P0 1.0 + #define FXAA_QUALITY__P1 1.5 + #define FXAA_QUALITY__P2 3.0 + #define FXAA_QUALITY__P3 12.0 +#endif +/*--------------------------------------------------------------------------*/ +#if (FXAA_QUALITY__PRESET == 12) + #define FXAA_QUALITY__PS 5 + #define FXAA_QUALITY__P0 1.0 + #define FXAA_QUALITY__P1 1.5 + #define FXAA_QUALITY__P2 2.0 + #define FXAA_QUALITY__P3 4.0 + #define FXAA_QUALITY__P4 12.0 +#endif +/*--------------------------------------------------------------------------*/ +#if (FXAA_QUALITY__PRESET == 13) + #define FXAA_QUALITY__PS 6 + #define FXAA_QUALITY__P0 1.0 + #define FXAA_QUALITY__P1 1.5 + #define FXAA_QUALITY__P2 2.0 + #define FXAA_QUALITY__P3 2.0 + #define FXAA_QUALITY__P4 4.0 + #define FXAA_QUALITY__P5 12.0 +#endif +/*--------------------------------------------------------------------------*/ +#if (FXAA_QUALITY__PRESET == 14) + #define FXAA_QUALITY__PS 7 + #define FXAA_QUALITY__P0 1.0 + #define FXAA_QUALITY__P1 1.5 + #define FXAA_QUALITY__P2 2.0 + #define FXAA_QUALITY__P3 2.0 + #define FXAA_QUALITY__P4 2.0 + #define FXAA_QUALITY__P5 4.0 + #define FXAA_QUALITY__P6 12.0 +#endif +/*--------------------------------------------------------------------------*/ +#if (FXAA_QUALITY__PRESET == 15) + #define FXAA_QUALITY__PS 8 + #define FXAA_QUALITY__P0 1.0 + #define FXAA_QUALITY__P1 1.5 + #define FXAA_QUALITY__P2 2.0 + #define FXAA_QUALITY__P3 2.0 + #define FXAA_QUALITY__P4 2.0 + #define FXAA_QUALITY__P5 2.0 + #define FXAA_QUALITY__P6 4.0 + #define FXAA_QUALITY__P7 12.0 +#endif + +/*============================================================================ + FXAA QUALITY - LOW DITHER PRESETS +============================================================================*/ +#if (FXAA_QUALITY__PRESET == 20) + #define FXAA_QUALITY__PS 3 + #define FXAA_QUALITY__P0 1.5 + #define FXAA_QUALITY__P1 2.0 + #define FXAA_QUALITY__P2 8.0 +#endif +/*--------------------------------------------------------------------------*/ +#if (FXAA_QUALITY__PRESET == 21) + #define FXAA_QUALITY__PS 4 + #define FXAA_QUALITY__P0 1.0 + #define FXAA_QUALITY__P1 1.5 + #define FXAA_QUALITY__P2 2.0 + #define FXAA_QUALITY__P3 8.0 +#endif +/*--------------------------------------------------------------------------*/ +#if (FXAA_QUALITY__PRESET == 22) + #define FXAA_QUALITY__PS 5 + #define FXAA_QUALITY__P0 1.0 + #define FXAA_QUALITY__P1 1.5 + #define FXAA_QUALITY__P2 2.0 + #define FXAA_QUALITY__P3 2.0 + #define FXAA_QUALITY__P4 8.0 +#endif +/*--------------------------------------------------------------------------*/ +#if (FXAA_QUALITY__PRESET == 23) + #define FXAA_QUALITY__PS 6 + #define FXAA_QUALITY__P0 1.0 + #define FXAA_QUALITY__P1 1.5 + #define FXAA_QUALITY__P2 2.0 + #define FXAA_QUALITY__P3 2.0 + #define FXAA_QUALITY__P4 2.0 + #define FXAA_QUALITY__P5 8.0 +#endif +/*--------------------------------------------------------------------------*/ +#if (FXAA_QUALITY__PRESET == 24) + #define FXAA_QUALITY__PS 7 + #define FXAA_QUALITY__P0 1.0 + #define FXAA_QUALITY__P1 1.5 + #define FXAA_QUALITY__P2 2.0 + #define FXAA_QUALITY__P3 2.0 + #define FXAA_QUALITY__P4 2.0 + #define FXAA_QUALITY__P5 3.0 + #define FXAA_QUALITY__P6 8.0 +#endif +/*--------------------------------------------------------------------------*/ +#if (FXAA_QUALITY__PRESET == 25) + #define FXAA_QUALITY__PS 8 + #define FXAA_QUALITY__P0 1.0 + #define FXAA_QUALITY__P1 1.5 + #define FXAA_QUALITY__P2 2.0 + #define FXAA_QUALITY__P3 2.0 + #define FXAA_QUALITY__P4 2.0 + #define FXAA_QUALITY__P5 2.0 + #define FXAA_QUALITY__P6 4.0 + #define FXAA_QUALITY__P7 8.0 +#endif +/*--------------------------------------------------------------------------*/ +#if (FXAA_QUALITY__PRESET == 26) + #define FXAA_QUALITY__PS 9 + #define FXAA_QUALITY__P0 1.0 + #define FXAA_QUALITY__P1 1.5 + #define FXAA_QUALITY__P2 2.0 + #define FXAA_QUALITY__P3 2.0 + #define FXAA_QUALITY__P4 2.0 + #define FXAA_QUALITY__P5 2.0 + #define FXAA_QUALITY__P6 2.0 + #define FXAA_QUALITY__P7 4.0 + #define FXAA_QUALITY__P8 8.0 +#endif +/*--------------------------------------------------------------------------*/ +#if (FXAA_QUALITY__PRESET == 27) + #define FXAA_QUALITY__PS 10 + #define FXAA_QUALITY__P0 1.0 + #define FXAA_QUALITY__P1 1.5 + #define FXAA_QUALITY__P2 2.0 + #define FXAA_QUALITY__P3 2.0 + #define FXAA_QUALITY__P4 2.0 + #define FXAA_QUALITY__P5 2.0 + #define FXAA_QUALITY__P6 2.0 + #define FXAA_QUALITY__P7 2.0 + #define FXAA_QUALITY__P8 4.0 + #define FXAA_QUALITY__P9 8.0 +#endif +/*--------------------------------------------------------------------------*/ +#if (FXAA_QUALITY__PRESET == 28) + #define FXAA_QUALITY__PS 11 + #define FXAA_QUALITY__P0 1.0 + #define FXAA_QUALITY__P1 1.5 + #define FXAA_QUALITY__P2 2.0 + #define FXAA_QUALITY__P3 2.0 + #define FXAA_QUALITY__P4 2.0 + #define FXAA_QUALITY__P5 2.0 + #define FXAA_QUALITY__P6 2.0 + #define FXAA_QUALITY__P7 2.0 + #define FXAA_QUALITY__P8 2.0 + #define FXAA_QUALITY__P9 4.0 + #define FXAA_QUALITY__P10 8.0 +#endif +/*--------------------------------------------------------------------------*/ +#if (FXAA_QUALITY__PRESET == 29) + #define FXAA_QUALITY__PS 12 + #define FXAA_QUALITY__P0 1.0 + #define FXAA_QUALITY__P1 1.5 + #define FXAA_QUALITY__P2 2.0 + #define FXAA_QUALITY__P3 2.0 + #define FXAA_QUALITY__P4 2.0 + #define FXAA_QUALITY__P5 2.0 + #define FXAA_QUALITY__P6 2.0 + #define FXAA_QUALITY__P7 2.0 + #define FXAA_QUALITY__P8 2.0 + #define FXAA_QUALITY__P9 2.0 + #define FXAA_QUALITY__P10 4.0 + #define FXAA_QUALITY__P11 8.0 +#endif + +/*============================================================================ + FXAA QUALITY - EXTREME QUALITY +============================================================================*/ +#if (FXAA_QUALITY__PRESET == 39) + #define FXAA_QUALITY__PS 12 + #define FXAA_QUALITY__P0 1.0 + #define FXAA_QUALITY__P1 1.0 + #define FXAA_QUALITY__P2 1.0 + #define FXAA_QUALITY__P3 1.0 + #define FXAA_QUALITY__P4 1.0 + #define FXAA_QUALITY__P5 1.5 + #define FXAA_QUALITY__P6 2.0 + #define FXAA_QUALITY__P7 2.0 + #define FXAA_QUALITY__P8 2.0 + #define FXAA_QUALITY__P9 2.0 + #define FXAA_QUALITY__P10 4.0 + #define FXAA_QUALITY__P11 8.0 +#endif + + + +/*============================================================================ + + API PORTING + +============================================================================*/ +#if (FXAA_GLSL_120 == 1) || (FXAA_GLSL_130 == 1) + #define FxaaBool bool + #define FxaaDiscard discard + #define FxaaFloat float + #define FxaaFloat2 vec2 + #define FxaaFloat3 vec3 + #define FxaaFloat4 vec4 + #define FxaaHalf float + #define FxaaHalf2 vec2 + #define FxaaHalf3 vec3 + #define FxaaHalf4 vec4 + #define FxaaInt2 ivec2 + #define FxaaSat(x) clamp(x, 0.0, 1.0) + #define FxaaTex sampler2D +#else + #define FxaaBool bool + #define FxaaDiscard clip(-1) + #define FxaaFloat float + #define FxaaFloat2 float2 + #define FxaaFloat3 float3 + #define FxaaFloat4 float4 + #define FxaaHalf half + #define FxaaHalf2 half2 + #define FxaaHalf3 half3 + #define FxaaHalf4 half4 + #define FxaaSat(x) saturate(x) +#endif +/*--------------------------------------------------------------------------*/ +#if (FXAA_GLSL_120 == 1) + // Requires, + // #version 120 + // And at least, + // #extension GL_EXT_gpu_shader4 : enable + // (or set FXAA_FAST_PIXEL_OFFSET 1 to work like DX9) + #define FxaaTexTop(t, p) texture2DLod(t, p, 0.0) + #if (FXAA_FAST_PIXEL_OFFSET == 1) + #define FxaaTexOff(t, p, o, r) texture2DLodOffset(t, p, 0.0, o) + #else + #define FxaaTexOff(t, p, o, r) texture2DLod(t, p + (o * r), 0.0) + #endif + #if (FXAA_GATHER4_ALPHA == 1) + // use #extension GL_ARB_gpu_shader5 : enable + #define FxaaTexAlpha4(t, p) textureGather(t, p, 3) + #define FxaaTexOffAlpha4(t, p, o) textureGatherOffset(t, p, o, 3) + #define FxaaTexGreen4(t, p) textureGather(t, p, 1) + #define FxaaTexOffGreen4(t, p, o) textureGatherOffset(t, p, o, 1) + #endif +#endif +/*--------------------------------------------------------------------------*/ +#if (FXAA_GLSL_130 == 1) + // Requires "#version 130" or better + #define FxaaTexTop(t, p) textureLod(t, p, 0.0) + #define FxaaTexOff(t, p, o, r) textureLodOffset(t, p, 0.0, o) + #if (FXAA_GATHER4_ALPHA == 1) + // use #extension GL_ARB_gpu_shader5 : enable + #define FxaaTexAlpha4(t, p) textureGather(t, p, 3) + #define FxaaTexOffAlpha4(t, p, o) textureGatherOffset(t, p, o, 3) + #define FxaaTexGreen4(t, p) textureGather(t, p, 1) + #define FxaaTexOffGreen4(t, p, o) textureGatherOffset(t, p, o, 1) + #endif +#endif +/*--------------------------------------------------------------------------*/ +#if (FXAA_HLSL_3 == 1) || (FXAA_360 == 1) || (FXAA_PS3 == 1) + #define FxaaInt2 float2 + #define FxaaTex sampler2D + #define FxaaTexTop(t, p) tex2Dlod(t, float4(p, 0.0, 0.0)) + #define FxaaTexOff(t, p, o, r) tex2Dlod(t, float4(p + (o * r), 0, 0)) +#endif +/*--------------------------------------------------------------------------*/ +#if (FXAA_HLSL_4 == 1) + #define FxaaInt2 int2 + struct FxaaTex { SamplerState smpl; Texture2D tex; }; + #define FxaaTexTop(t, p) t.tex.SampleLevel(t.smpl, p, 0.0) + #define FxaaTexOff(t, p, o, r) t.tex.SampleLevel(t.smpl, p, 0.0, o) +#endif +/*--------------------------------------------------------------------------*/ +#if (FXAA_HLSL_5 == 1) + #define FxaaInt2 int2 + struct FxaaTex { SamplerState smpl; Texture2D tex; }; + #define FxaaTexTop(t, p) t.tex.SampleLevel(t.smpl, p, 0.0) + #define FxaaTexOff(t, p, o, r) t.tex.SampleLevel(t.smpl, p, 0.0, o) + #define FxaaTexAlpha4(t, p) t.tex.GatherAlpha(t.smpl, p) + #define FxaaTexOffAlpha4(t, p, o) t.tex.GatherAlpha(t.smpl, p, o) + #define FxaaTexGreen4(t, p) t.tex.GatherGreen(t.smpl, p) + #define FxaaTexOffGreen4(t, p, o) t.tex.GatherGreen(t.smpl, p, o) +#endif + + +/*============================================================================ + GREEN AS LUMA OPTION SUPPORT FUNCTION +============================================================================*/ +#if (FXAA_GREEN_AS_LUMA == 0) + FxaaFloat FxaaLuma(FxaaFloat4 rgba) { return rgba.w; } +#else + FxaaFloat FxaaLuma(FxaaFloat4 rgba) { return rgba.y; } +#endif + + + + +/*============================================================================ + + FXAA3 QUALITY - PC + +============================================================================*/ +#if (FXAA_PC == 1) +/*--------------------------------------------------------------------------*/ +FxaaFloat4 FxaaPixelShader( + // + // Use noperspective interpolation here (turn off perspective interpolation). + // {xy} = center of pixel + FxaaFloat2 pos, + // + // Used only for FXAA Console, and not used on the 360 version. + // Use noperspective interpolation here (turn off perspective interpolation). + // {xy__} = upper left of pixel + // {__zw} = lower right of pixel + FxaaFloat4 fxaaConsolePosPos, + // + // Input color texture. + // {rgb_} = color in linear or perceptual color space + // if (FXAA_GREEN_AS_LUMA == 0) + // {___a} = luma in perceptual color space (not linear) + FxaaTex tex, + // + // Only used on the optimized 360 version of FXAA Console. + // For everything but 360, just use the same input here as for "tex". + // For 360, same texture, just alias with a 2nd sampler. + // This sampler needs to have an exponent bias of -1. + FxaaTex fxaaConsole360TexExpBiasNegOne, + // + // Only used on the optimized 360 version of FXAA Console. + // For everything but 360, just use the same input here as for "tex". + // For 360, same texture, just alias with a 3nd sampler. + // This sampler needs to have an exponent bias of -2. + FxaaTex fxaaConsole360TexExpBiasNegTwo, + // + // Only used on FXAA Quality. + // This must be from a constant/uniform. + // {x_} = 1.0/screenWidthInPixels + // {_y} = 1.0/screenHeightInPixels + FxaaFloat2 fxaaQualityRcpFrame, + // + // Only used on FXAA Console. + // This must be from a constant/uniform. + // This effects sub-pixel AA quality and inversely sharpness. + // Where N ranges between, + // N = 0.50 (default) + // N = 0.33 (sharper) + // {x___} = -N/screenWidthInPixels + // {_y__} = -N/screenHeightInPixels + // {__z_} = N/screenWidthInPixels + // {___w} = N/screenHeightInPixels + FxaaFloat4 fxaaConsoleRcpFrameOpt, + // + // Only used on FXAA Console. + // Not used on 360, but used on PS3 and PC. + // This must be from a constant/uniform. + // {x___} = -2.0/screenWidthInPixels + // {_y__} = -2.0/screenHeightInPixels + // {__z_} = 2.0/screenWidthInPixels + // {___w} = 2.0/screenHeightInPixels + FxaaFloat4 fxaaConsoleRcpFrameOpt2, + // + // Only used on FXAA Console. + // Only used on 360 in place of fxaaConsoleRcpFrameOpt2. + // This must be from a constant/uniform. + // {x___} = 8.0/screenWidthInPixels + // {_y__} = 8.0/screenHeightInPixels + // {__z_} = -4.0/screenWidthInPixels + // {___w} = -4.0/screenHeightInPixels + FxaaFloat4 fxaaConsole360RcpFrameOpt2, + // + // Only used on FXAA Quality. + // This used to be the FXAA_QUALITY__SUBPIX define. + // It is here now to allow easier tuning. + // Choose the amount of sub-pixel aliasing removal. + // This can effect sharpness. + // 1.00 - upper limit (softer) + // 0.75 - default amount of filtering + // 0.50 - lower limit (sharper, less sub-pixel aliasing removal) + // 0.25 - almost off + // 0.00 - completely off + FxaaFloat fxaaQualitySubpix, + // + // Only used on FXAA Quality. + // This used to be the FXAA_QUALITY__EDGE_THRESHOLD define. + // It is here now to allow easier tuning. + // The minimum amount of local contrast required to apply algorithm. + // 0.333 - too little (faster) + // 0.250 - low quality + // 0.166 - default + // 0.125 - high quality + // 0.063 - overkill (slower) + FxaaFloat fxaaQualityEdgeThreshold, + // + // Only used on FXAA Quality. + // This used to be the FXAA_QUALITY__EDGE_THRESHOLD_MIN define. + // It is here now to allow easier tuning. + // Trims the algorithm from processing darks. + // 0.0833 - upper limit (default, the start of visible unfiltered edges) + // 0.0625 - high quality (faster) + // 0.0312 - visible limit (slower) + // Special notes when using FXAA_GREEN_AS_LUMA, + // Likely want to set this to zero. + // As colors that are mostly not-green + // will appear very dark in the green channel! + // Tune by looking at mostly non-green content, + // then start at zero and increase until aliasing is a problem. + FxaaFloat fxaaQualityEdgeThresholdMin, + // + // Only used on FXAA Console. + // This used to be the FXAA_CONSOLE__EDGE_SHARPNESS define. + // It is here now to allow easier tuning. + // This does not effect PS3, as this needs to be compiled in. + // Use FXAA_CONSOLE__PS3_EDGE_SHARPNESS for PS3. + // Due to the PS3 being ALU bound, + // there are only three safe values here: 2 and 4 and 8. + // These options use the shaders ability to a free *|/ by 2|4|8. + // For all other platforms can be a non-power of two. + // 8.0 is sharper (default!!!) + // 4.0 is softer + // 2.0 is really soft (good only for vector graphics inputs) + FxaaFloat fxaaConsoleEdgeSharpness, + // + // Only used on FXAA Console. + // This used to be the FXAA_CONSOLE__EDGE_THRESHOLD define. + // It is here now to allow easier tuning. + // This does not effect PS3, as this needs to be compiled in. + // Use FXAA_CONSOLE__PS3_EDGE_THRESHOLD for PS3. + // Due to the PS3 being ALU bound, + // there are only two safe values here: 1/4 and 1/8. + // These options use the shaders ability to a free *|/ by 2|4|8. + // The console setting has a different mapping than the quality setting. + // Other platforms can use other values. + // 0.125 leaves less aliasing, but is softer (default!!!) + // 0.25 leaves more aliasing, and is sharper + FxaaFloat fxaaConsoleEdgeThreshold, + // + // Only used on FXAA Console. + // This used to be the FXAA_CONSOLE__EDGE_THRESHOLD_MIN define. + // It is here now to allow easier tuning. + // Trims the algorithm from processing darks. + // The console setting has a different mapping than the quality setting. + // This only applies when FXAA_EARLY_EXIT is 1. + // This does not apply to PS3, + // PS3 was simplified to avoid more shader instructions. + // 0.06 - faster but more aliasing in darks + // 0.05 - default + // 0.04 - slower and less aliasing in darks + // Special notes when using FXAA_GREEN_AS_LUMA, + // Likely want to set this to zero. + // As colors that are mostly not-green + // will appear very dark in the green channel! + // Tune by looking at mostly non-green content, + // then start at zero and increase until aliasing is a problem. + FxaaFloat fxaaConsoleEdgeThresholdMin, + // + // Extra constants for 360 FXAA Console only. + // Use zeros or anything else for other platforms. + // These must be in physical constant registers and NOT immedates. + // Immedates will result in compiler un-optimizing. + // {xyzw} = float4(1.0, -1.0, 0.25, -0.25) + FxaaFloat4 fxaaConsole360ConstDir +) { +/*--------------------------------------------------------------------------*/ + FxaaFloat2 posM; + posM.x = pos.x; + posM.y = pos.y; + #if (FXAA_GATHER4_ALPHA == 1) + #if (FXAA_DISCARD == 0) + FxaaFloat4 rgbyM = FxaaTexTop(tex, posM); + #if (FXAA_GREEN_AS_LUMA == 0) + #define lumaM rgbyM.w + #else + #define lumaM rgbyM.y + #endif + #endif + #if (FXAA_GREEN_AS_LUMA == 0) + FxaaFloat4 luma4A = FxaaTexAlpha4(tex, posM); + FxaaFloat4 luma4B = FxaaTexOffAlpha4(tex, posM, FxaaInt2(-1, -1)); + #else + FxaaFloat4 luma4A = FxaaTexGreen4(tex, posM); + FxaaFloat4 luma4B = FxaaTexOffGreen4(tex, posM, FxaaInt2(-1, -1)); + #endif + #if (FXAA_DISCARD == 1) + #define lumaM luma4A.w + #endif + #define lumaE luma4A.z + #define lumaS luma4A.x + #define lumaSE luma4A.y + #define lumaNW luma4B.w + #define lumaN luma4B.z + #define lumaW luma4B.x + #else + FxaaFloat4 rgbyM = FxaaTexTop(tex, posM); + #if (FXAA_GREEN_AS_LUMA == 0) + #define lumaM rgbyM.w + #else + #define lumaM rgbyM.y + #endif + FxaaFloat lumaS = FxaaLuma(FxaaTexOff(tex, posM, FxaaInt2( 0, 1), fxaaQualityRcpFrame.xy)); + FxaaFloat lumaE = FxaaLuma(FxaaTexOff(tex, posM, FxaaInt2( 1, 0), fxaaQualityRcpFrame.xy)); + FxaaFloat lumaN = FxaaLuma(FxaaTexOff(tex, posM, FxaaInt2( 0,-1), fxaaQualityRcpFrame.xy)); + FxaaFloat lumaW = FxaaLuma(FxaaTexOff(tex, posM, FxaaInt2(-1, 0), fxaaQualityRcpFrame.xy)); + #endif +/*--------------------------------------------------------------------------*/ + FxaaFloat maxSM = max(lumaS, lumaM); + FxaaFloat minSM = min(lumaS, lumaM); + FxaaFloat maxESM = max(lumaE, maxSM); + FxaaFloat minESM = min(lumaE, minSM); + FxaaFloat maxWN = max(lumaN, lumaW); + FxaaFloat minWN = min(lumaN, lumaW); + FxaaFloat rangeMax = max(maxWN, maxESM); + FxaaFloat rangeMin = min(minWN, minESM); + FxaaFloat rangeMaxScaled = rangeMax * fxaaQualityEdgeThreshold; + FxaaFloat range = rangeMax - rangeMin; + FxaaFloat rangeMaxClamped = max(fxaaQualityEdgeThresholdMin, rangeMaxScaled); + FxaaBool earlyExit = range < rangeMaxClamped; +/*--------------------------------------------------------------------------*/ + if(earlyExit) + #if (FXAA_DISCARD == 1) + FxaaDiscard; + #else + return rgbyM; + #endif +/*--------------------------------------------------------------------------*/ + #if (FXAA_GATHER4_ALPHA == 0) + FxaaFloat lumaNW = FxaaLuma(FxaaTexOff(tex, posM, FxaaInt2(-1,-1), fxaaQualityRcpFrame.xy)); + FxaaFloat lumaSE = FxaaLuma(FxaaTexOff(tex, posM, FxaaInt2( 1, 1), fxaaQualityRcpFrame.xy)); + FxaaFloat lumaNE = FxaaLuma(FxaaTexOff(tex, posM, FxaaInt2( 1,-1), fxaaQualityRcpFrame.xy)); + FxaaFloat lumaSW = FxaaLuma(FxaaTexOff(tex, posM, FxaaInt2(-1, 1), fxaaQualityRcpFrame.xy)); + #else + FxaaFloat lumaNE = FxaaLuma(FxaaTexOff(tex, posM, FxaaInt2(1, -1), fxaaQualityRcpFrame.xy)); + FxaaFloat lumaSW = FxaaLuma(FxaaTexOff(tex, posM, FxaaInt2(-1, 1), fxaaQualityRcpFrame.xy)); + #endif +/*--------------------------------------------------------------------------*/ + FxaaFloat lumaNS = lumaN + lumaS; + FxaaFloat lumaWE = lumaW + lumaE; + FxaaFloat subpixRcpRange = 1.0/range; + FxaaFloat subpixNSWE = lumaNS + lumaWE; + FxaaFloat edgeHorz1 = (-2.0 * lumaM) + lumaNS; + FxaaFloat edgeVert1 = (-2.0 * lumaM) + lumaWE; +/*--------------------------------------------------------------------------*/ + FxaaFloat lumaNESE = lumaNE + lumaSE; + FxaaFloat lumaNWNE = lumaNW + lumaNE; + FxaaFloat edgeHorz2 = (-2.0 * lumaE) + lumaNESE; + FxaaFloat edgeVert2 = (-2.0 * lumaN) + lumaNWNE; +/*--------------------------------------------------------------------------*/ + FxaaFloat lumaNWSW = lumaNW + lumaSW; + FxaaFloat lumaSWSE = lumaSW + lumaSE; + FxaaFloat edgeHorz4 = (abs(edgeHorz1) * 2.0) + abs(edgeHorz2); + FxaaFloat edgeVert4 = (abs(edgeVert1) * 2.0) + abs(edgeVert2); + FxaaFloat edgeHorz3 = (-2.0 * lumaW) + lumaNWSW; + FxaaFloat edgeVert3 = (-2.0 * lumaS) + lumaSWSE; + FxaaFloat edgeHorz = abs(edgeHorz3) + edgeHorz4; + FxaaFloat edgeVert = abs(edgeVert3) + edgeVert4; +/*--------------------------------------------------------------------------*/ + FxaaFloat subpixNWSWNESE = lumaNWSW + lumaNESE; + FxaaFloat lengthSign = fxaaQualityRcpFrame.x; + FxaaBool horzSpan = edgeHorz >= edgeVert; + FxaaFloat subpixA = subpixNSWE * 2.0 + subpixNWSWNESE; +/*--------------------------------------------------------------------------*/ + if(!horzSpan) lumaN = lumaW; + if(!horzSpan) lumaS = lumaE; + if(horzSpan) lengthSign = fxaaQualityRcpFrame.y; + FxaaFloat subpixB = (subpixA * (1.0/12.0)) - lumaM; +/*--------------------------------------------------------------------------*/ + FxaaFloat gradientN = lumaN - lumaM; + FxaaFloat gradientS = lumaS - lumaM; + FxaaFloat lumaNN = lumaN + lumaM; + FxaaFloat lumaSS = lumaS + lumaM; + FxaaBool pairN = abs(gradientN) >= abs(gradientS); + FxaaFloat gradient = max(abs(gradientN), abs(gradientS)); + if(pairN) lengthSign = -lengthSign; + FxaaFloat subpixC = FxaaSat(abs(subpixB) * subpixRcpRange); +/*--------------------------------------------------------------------------*/ + FxaaFloat2 posB; + posB.x = posM.x; + posB.y = posM.y; + FxaaFloat2 offNP; + offNP.x = (!horzSpan) ? 0.0 : fxaaQualityRcpFrame.x; + offNP.y = ( horzSpan) ? 0.0 : fxaaQualityRcpFrame.y; + if(!horzSpan) posB.x += lengthSign * 0.5; + if( horzSpan) posB.y += lengthSign * 0.5; +/*--------------------------------------------------------------------------*/ + FxaaFloat2 posN; + posN.x = posB.x - offNP.x * FXAA_QUALITY__P0; + posN.y = posB.y - offNP.y * FXAA_QUALITY__P0; + FxaaFloat2 posP; + posP.x = posB.x + offNP.x * FXAA_QUALITY__P0; + posP.y = posB.y + offNP.y * FXAA_QUALITY__P0; + FxaaFloat subpixD = ((-2.0)*subpixC) + 3.0; + FxaaFloat lumaEndN = FxaaLuma(FxaaTexTop(tex, posN)); + FxaaFloat subpixE = subpixC * subpixC; + FxaaFloat lumaEndP = FxaaLuma(FxaaTexTop(tex, posP)); +/*--------------------------------------------------------------------------*/ + if(!pairN) lumaNN = lumaSS; + FxaaFloat gradientScaled = gradient * 1.0/4.0; + FxaaFloat lumaMM = lumaM - lumaNN * 0.5; + FxaaFloat subpixF = subpixD * subpixE; + FxaaBool lumaMLTZero = lumaMM < 0.0; +/*--------------------------------------------------------------------------*/ + lumaEndN -= lumaNN * 0.5; + lumaEndP -= lumaNN * 0.5; + FxaaBool doneN = abs(lumaEndN) >= gradientScaled; + FxaaBool doneP = abs(lumaEndP) >= gradientScaled; + if(!doneN) posN.x -= offNP.x * FXAA_QUALITY__P1; + if(!doneN) posN.y -= offNP.y * FXAA_QUALITY__P1; + FxaaBool doneNP = (!doneN) || (!doneP); + if(!doneP) posP.x += offNP.x * FXAA_QUALITY__P1; + if(!doneP) posP.y += offNP.y * FXAA_QUALITY__P1; +/*--------------------------------------------------------------------------*/ + if(doneNP) { + if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy)); + if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy)); + if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5; + if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5; + doneN = abs(lumaEndN) >= gradientScaled; + doneP = abs(lumaEndP) >= gradientScaled; + if(!doneN) posN.x -= offNP.x * FXAA_QUALITY__P2; + if(!doneN) posN.y -= offNP.y * FXAA_QUALITY__P2; + doneNP = (!doneN) || (!doneP); + if(!doneP) posP.x += offNP.x * FXAA_QUALITY__P2; + if(!doneP) posP.y += offNP.y * FXAA_QUALITY__P2; +/*--------------------------------------------------------------------------*/ + #if (FXAA_QUALITY__PS > 3) + if(doneNP) { + if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy)); + if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy)); + if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5; + if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5; + doneN = abs(lumaEndN) >= gradientScaled; + doneP = abs(lumaEndP) >= gradientScaled; + if(!doneN) posN.x -= offNP.x * FXAA_QUALITY__P3; + if(!doneN) posN.y -= offNP.y * FXAA_QUALITY__P3; + doneNP = (!doneN) || (!doneP); + if(!doneP) posP.x += offNP.x * FXAA_QUALITY__P3; + if(!doneP) posP.y += offNP.y * FXAA_QUALITY__P3; +/*--------------------------------------------------------------------------*/ + #if (FXAA_QUALITY__PS > 4) + if(doneNP) { + if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy)); + if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy)); + if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5; + if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5; + doneN = abs(lumaEndN) >= gradientScaled; + doneP = abs(lumaEndP) >= gradientScaled; + if(!doneN) posN.x -= offNP.x * FXAA_QUALITY__P4; + if(!doneN) posN.y -= offNP.y * FXAA_QUALITY__P4; + doneNP = (!doneN) || (!doneP); + if(!doneP) posP.x += offNP.x * FXAA_QUALITY__P4; + if(!doneP) posP.y += offNP.y * FXAA_QUALITY__P4; +/*--------------------------------------------------------------------------*/ + #if (FXAA_QUALITY__PS > 5) + if(doneNP) { + if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy)); + if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy)); + if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5; + if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5; + doneN = abs(lumaEndN) >= gradientScaled; + doneP = abs(lumaEndP) >= gradientScaled; + if(!doneN) posN.x -= offNP.x * FXAA_QUALITY__P5; + if(!doneN) posN.y -= offNP.y * FXAA_QUALITY__P5; + doneNP = (!doneN) || (!doneP); + if(!doneP) posP.x += offNP.x * FXAA_QUALITY__P5; + if(!doneP) posP.y += offNP.y * FXAA_QUALITY__P5; +/*--------------------------------------------------------------------------*/ + #if (FXAA_QUALITY__PS > 6) + if(doneNP) { + if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy)); + if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy)); + if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5; + if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5; + doneN = abs(lumaEndN) >= gradientScaled; + doneP = abs(lumaEndP) >= gradientScaled; + if(!doneN) posN.x -= offNP.x * FXAA_QUALITY__P6; + if(!doneN) posN.y -= offNP.y * FXAA_QUALITY__P6; + doneNP = (!doneN) || (!doneP); + if(!doneP) posP.x += offNP.x * FXAA_QUALITY__P6; + if(!doneP) posP.y += offNP.y * FXAA_QUALITY__P6; +/*--------------------------------------------------------------------------*/ + #if (FXAA_QUALITY__PS > 7) + if(doneNP) { + if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy)); + if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy)); + if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5; + if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5; + doneN = abs(lumaEndN) >= gradientScaled; + doneP = abs(lumaEndP) >= gradientScaled; + if(!doneN) posN.x -= offNP.x * FXAA_QUALITY__P7; + if(!doneN) posN.y -= offNP.y * FXAA_QUALITY__P7; + doneNP = (!doneN) || (!doneP); + if(!doneP) posP.x += offNP.x * FXAA_QUALITY__P7; + if(!doneP) posP.y += offNP.y * FXAA_QUALITY__P7; +/*--------------------------------------------------------------------------*/ + #if (FXAA_QUALITY__PS > 8) + if(doneNP) { + if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy)); + if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy)); + if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5; + if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5; + doneN = abs(lumaEndN) >= gradientScaled; + doneP = abs(lumaEndP) >= gradientScaled; + if(!doneN) posN.x -= offNP.x * FXAA_QUALITY__P8; + if(!doneN) posN.y -= offNP.y * FXAA_QUALITY__P8; + doneNP = (!doneN) || (!doneP); + if(!doneP) posP.x += offNP.x * FXAA_QUALITY__P8; + if(!doneP) posP.y += offNP.y * FXAA_QUALITY__P8; +/*--------------------------------------------------------------------------*/ + #if (FXAA_QUALITY__PS > 9) + if(doneNP) { + if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy)); + if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy)); + if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5; + if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5; + doneN = abs(lumaEndN) >= gradientScaled; + doneP = abs(lumaEndP) >= gradientScaled; + if(!doneN) posN.x -= offNP.x * FXAA_QUALITY__P9; + if(!doneN) posN.y -= offNP.y * FXAA_QUALITY__P9; + doneNP = (!doneN) || (!doneP); + if(!doneP) posP.x += offNP.x * FXAA_QUALITY__P9; + if(!doneP) posP.y += offNP.y * FXAA_QUALITY__P9; +/*--------------------------------------------------------------------------*/ + #if (FXAA_QUALITY__PS > 10) + if(doneNP) { + if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy)); + if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy)); + if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5; + if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5; + doneN = abs(lumaEndN) >= gradientScaled; + doneP = abs(lumaEndP) >= gradientScaled; + if(!doneN) posN.x -= offNP.x * FXAA_QUALITY__P10; + if(!doneN) posN.y -= offNP.y * FXAA_QUALITY__P10; + doneNP = (!doneN) || (!doneP); + if(!doneP) posP.x += offNP.x * FXAA_QUALITY__P10; + if(!doneP) posP.y += offNP.y * FXAA_QUALITY__P10; +/*--------------------------------------------------------------------------*/ + #if (FXAA_QUALITY__PS > 11) + if(doneNP) { + if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy)); + if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy)); + if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5; + if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5; + doneN = abs(lumaEndN) >= gradientScaled; + doneP = abs(lumaEndP) >= gradientScaled; + if(!doneN) posN.x -= offNP.x * FXAA_QUALITY__P11; + if(!doneN) posN.y -= offNP.y * FXAA_QUALITY__P11; + doneNP = (!doneN) || (!doneP); + if(!doneP) posP.x += offNP.x * FXAA_QUALITY__P11; + if(!doneP) posP.y += offNP.y * FXAA_QUALITY__P11; +/*--------------------------------------------------------------------------*/ + #if (FXAA_QUALITY__PS > 12) + if(doneNP) { + if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy)); + if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy)); + if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5; + if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5; + doneN = abs(lumaEndN) >= gradientScaled; + doneP = abs(lumaEndP) >= gradientScaled; + if(!doneN) posN.x -= offNP.x * FXAA_QUALITY__P12; + if(!doneN) posN.y -= offNP.y * FXAA_QUALITY__P12; + doneNP = (!doneN) || (!doneP); + if(!doneP) posP.x += offNP.x * FXAA_QUALITY__P12; + if(!doneP) posP.y += offNP.y * FXAA_QUALITY__P12; +/*--------------------------------------------------------------------------*/ + } + #endif +/*--------------------------------------------------------------------------*/ + } + #endif +/*--------------------------------------------------------------------------*/ + } + #endif +/*--------------------------------------------------------------------------*/ + } + #endif +/*--------------------------------------------------------------------------*/ + } + #endif +/*--------------------------------------------------------------------------*/ + } + #endif +/*--------------------------------------------------------------------------*/ + } + #endif +/*--------------------------------------------------------------------------*/ + } + #endif +/*--------------------------------------------------------------------------*/ + } + #endif +/*--------------------------------------------------------------------------*/ + } + #endif +/*--------------------------------------------------------------------------*/ + } +/*--------------------------------------------------------------------------*/ + FxaaFloat dstN = posM.x - posN.x; + FxaaFloat dstP = posP.x - posM.x; + if(!horzSpan) dstN = posM.y - posN.y; + if(!horzSpan) dstP = posP.y - posM.y; +/*--------------------------------------------------------------------------*/ + FxaaBool goodSpanN = (lumaEndN < 0.0) != lumaMLTZero; + FxaaFloat spanLength = (dstP + dstN); + FxaaBool goodSpanP = (lumaEndP < 0.0) != lumaMLTZero; + FxaaFloat spanLengthRcp = 1.0/spanLength; +/*--------------------------------------------------------------------------*/ + FxaaBool directionN = dstN < dstP; + FxaaFloat dst = min(dstN, dstP); + FxaaBool goodSpan = directionN ? goodSpanN : goodSpanP; + FxaaFloat subpixG = subpixF * subpixF; + FxaaFloat pixelOffset = (dst * (-spanLengthRcp)) + 0.5; + FxaaFloat subpixH = subpixG * fxaaQualitySubpix; +/*--------------------------------------------------------------------------*/ + FxaaFloat pixelOffsetGood = goodSpan ? pixelOffset : 0.0; + FxaaFloat pixelOffsetSubpix = max(pixelOffsetGood, subpixH); + if(!horzSpan) posM.x += pixelOffsetSubpix * lengthSign; + if( horzSpan) posM.y += pixelOffsetSubpix * lengthSign; + #if (FXAA_DISCARD == 1) + return FxaaTexTop(tex, posM); + #else + return FxaaFloat4(FxaaTexTop(tex, posM).xyz, lumaM); + #endif +} +/*==========================================================================*/ +#endif + + + + +/*============================================================================ + + FXAA3 CONSOLE - PC VERSION + +------------------------------------------------------------------------------ +Instead of using this on PC, I'd suggest just using FXAA Quality with + #define FXAA_QUALITY__PRESET 10 +Or + #define FXAA_QUALITY__PRESET 20 +Either are higher qualilty and almost as fast as this on modern PC GPUs. +============================================================================*/ +#if (FXAA_PC_CONSOLE == 1) +/*--------------------------------------------------------------------------*/ +FxaaFloat4 FxaaPixelShader( + // See FXAA Quality FxaaPixelShader() source for docs on Inputs! + FxaaFloat2 pos, + FxaaFloat4 fxaaConsolePosPos, + FxaaTex tex, + FxaaTex fxaaConsole360TexExpBiasNegOne, + FxaaTex fxaaConsole360TexExpBiasNegTwo, + FxaaFloat2 fxaaQualityRcpFrame, + FxaaFloat4 fxaaConsoleRcpFrameOpt, + FxaaFloat4 fxaaConsoleRcpFrameOpt2, + FxaaFloat4 fxaaConsole360RcpFrameOpt2, + FxaaFloat fxaaQualitySubpix, + FxaaFloat fxaaQualityEdgeThreshold, + FxaaFloat fxaaQualityEdgeThresholdMin, + FxaaFloat fxaaConsoleEdgeSharpness, + FxaaFloat fxaaConsoleEdgeThreshold, + FxaaFloat fxaaConsoleEdgeThresholdMin, + FxaaFloat4 fxaaConsole360ConstDir +) { +/*--------------------------------------------------------------------------*/ + FxaaFloat lumaNw = FxaaLuma(FxaaTexTop(tex, fxaaConsolePosPos.xy)); + FxaaFloat lumaSw = FxaaLuma(FxaaTexTop(tex, fxaaConsolePosPos.xw)); + FxaaFloat lumaNe = FxaaLuma(FxaaTexTop(tex, fxaaConsolePosPos.zy)); + FxaaFloat lumaSe = FxaaLuma(FxaaTexTop(tex, fxaaConsolePosPos.zw)); +/*--------------------------------------------------------------------------*/ + FxaaFloat4 rgbyM = FxaaTexTop(tex, pos.xy); + #if (FXAA_GREEN_AS_LUMA == 0) + FxaaFloat lumaM = rgbyM.w; + #else + FxaaFloat lumaM = rgbyM.y; + #endif +/*--------------------------------------------------------------------------*/ + FxaaFloat lumaMaxNwSw = max(lumaNw, lumaSw); + lumaNe += 1.0/384.0; + FxaaFloat lumaMinNwSw = min(lumaNw, lumaSw); +/*--------------------------------------------------------------------------*/ + FxaaFloat lumaMaxNeSe = max(lumaNe, lumaSe); + FxaaFloat lumaMinNeSe = min(lumaNe, lumaSe); +/*--------------------------------------------------------------------------*/ + FxaaFloat lumaMax = max(lumaMaxNeSe, lumaMaxNwSw); + FxaaFloat lumaMin = min(lumaMinNeSe, lumaMinNwSw); +/*--------------------------------------------------------------------------*/ + FxaaFloat lumaMaxScaled = lumaMax * fxaaConsoleEdgeThreshold; +/*--------------------------------------------------------------------------*/ + FxaaFloat lumaMinM = min(lumaMin, lumaM); + FxaaFloat lumaMaxScaledClamped = max(fxaaConsoleEdgeThresholdMin, lumaMaxScaled); + FxaaFloat lumaMaxM = max(lumaMax, lumaM); + FxaaFloat dirSwMinusNe = lumaSw - lumaNe; + FxaaFloat lumaMaxSubMinM = lumaMaxM - lumaMinM; + FxaaFloat dirSeMinusNw = lumaSe - lumaNw; + if(lumaMaxSubMinM < lumaMaxScaledClamped) return rgbyM; +/*--------------------------------------------------------------------------*/ + FxaaFloat2 dir; + dir.x = dirSwMinusNe + dirSeMinusNw; + dir.y = dirSwMinusNe - dirSeMinusNw; +/*--------------------------------------------------------------------------*/ + FxaaFloat2 dir1 = normalize(dir.xy); + FxaaFloat4 rgbyN1 = FxaaTexTop(tex, pos.xy - dir1 * fxaaConsoleRcpFrameOpt.zw); + FxaaFloat4 rgbyP1 = FxaaTexTop(tex, pos.xy + dir1 * fxaaConsoleRcpFrameOpt.zw); +/*--------------------------------------------------------------------------*/ + FxaaFloat dirAbsMinTimesC = min(abs(dir1.x), abs(dir1.y)) * fxaaConsoleEdgeSharpness; + FxaaFloat2 dir2 = clamp(dir1.xy / dirAbsMinTimesC, -2.0, 2.0); +/*--------------------------------------------------------------------------*/ + FxaaFloat4 rgbyN2 = FxaaTexTop(tex, pos.xy - dir2 * fxaaConsoleRcpFrameOpt2.zw); + FxaaFloat4 rgbyP2 = FxaaTexTop(tex, pos.xy + dir2 * fxaaConsoleRcpFrameOpt2.zw); +/*--------------------------------------------------------------------------*/ + FxaaFloat4 rgbyA = rgbyN1 + rgbyP1; + FxaaFloat4 rgbyB = ((rgbyN2 + rgbyP2) * 0.25) + (rgbyA * 0.25); +/*--------------------------------------------------------------------------*/ + #if (FXAA_GREEN_AS_LUMA == 0) + FxaaBool twoTap = (rgbyB.w < lumaMin) || (rgbyB.w > lumaMax); + #else + FxaaBool twoTap = (rgbyB.y < lumaMin) || (rgbyB.y > lumaMax); + #endif + if(twoTap) rgbyB.xyz = rgbyA.xyz * 0.5; + return rgbyB; } +/*==========================================================================*/ +#endif + + + +/*============================================================================ + + FXAA3 CONSOLE - 360 PIXEL SHADER + +------------------------------------------------------------------------------ +This optimized version thanks to suggestions from Andy Luedke. +Should be fully tex bound in all cases. +As of the FXAA 3.11 release, I have still not tested this code, +however I fixed a bug which was in both FXAA 3.9 and FXAA 3.10. +And note this is replacing the old unoptimized version. +If it does not work, please let me know so I can fix it. +============================================================================*/ +#if (FXAA_360 == 1) +/*--------------------------------------------------------------------------*/ +[reduceTempRegUsage(4)] +float4 FxaaPixelShader( + // See FXAA Quality FxaaPixelShader() source for docs on Inputs! + FxaaFloat2 pos, + FxaaFloat4 fxaaConsolePosPos, + FxaaTex tex, + FxaaTex fxaaConsole360TexExpBiasNegOne, + FxaaTex fxaaConsole360TexExpBiasNegTwo, + FxaaFloat2 fxaaQualityRcpFrame, + FxaaFloat4 fxaaConsoleRcpFrameOpt, + FxaaFloat4 fxaaConsoleRcpFrameOpt2, + FxaaFloat4 fxaaConsole360RcpFrameOpt2, + FxaaFloat fxaaQualitySubpix, + FxaaFloat fxaaQualityEdgeThreshold, + FxaaFloat fxaaQualityEdgeThresholdMin, + FxaaFloat fxaaConsoleEdgeSharpness, + FxaaFloat fxaaConsoleEdgeThreshold, + FxaaFloat fxaaConsoleEdgeThresholdMin, + FxaaFloat4 fxaaConsole360ConstDir +) { +/*--------------------------------------------------------------------------*/ + float4 lumaNwNeSwSe; + #if (FXAA_GREEN_AS_LUMA == 0) + asm { + tfetch2D lumaNwNeSwSe.w___, tex, pos.xy, OffsetX = -0.5, OffsetY = -0.5, UseComputedLOD=false + tfetch2D lumaNwNeSwSe._w__, tex, pos.xy, OffsetX = 0.5, OffsetY = -0.5, UseComputedLOD=false + tfetch2D lumaNwNeSwSe.__w_, tex, pos.xy, OffsetX = -0.5, OffsetY = 0.5, UseComputedLOD=false + tfetch2D lumaNwNeSwSe.___w, tex, pos.xy, OffsetX = 0.5, OffsetY = 0.5, UseComputedLOD=false + }; + #else + asm { + tfetch2D lumaNwNeSwSe.y___, tex, pos.xy, OffsetX = -0.5, OffsetY = -0.5, UseComputedLOD=false + tfetch2D lumaNwNeSwSe._y__, tex, pos.xy, OffsetX = 0.5, OffsetY = -0.5, UseComputedLOD=false + tfetch2D lumaNwNeSwSe.__y_, tex, pos.xy, OffsetX = -0.5, OffsetY = 0.5, UseComputedLOD=false + tfetch2D lumaNwNeSwSe.___y, tex, pos.xy, OffsetX = 0.5, OffsetY = 0.5, UseComputedLOD=false + }; + #endif +/*--------------------------------------------------------------------------*/ + lumaNwNeSwSe.y += 1.0/384.0; + float2 lumaMinTemp = min(lumaNwNeSwSe.xy, lumaNwNeSwSe.zw); + float2 lumaMaxTemp = max(lumaNwNeSwSe.xy, lumaNwNeSwSe.zw); + float lumaMin = min(lumaMinTemp.x, lumaMinTemp.y); + float lumaMax = max(lumaMaxTemp.x, lumaMaxTemp.y); +/*--------------------------------------------------------------------------*/ + float4 rgbyM = tex2Dlod(tex, float4(pos.xy, 0.0, 0.0)); + #if (FXAA_GREEN_AS_LUMA == 0) + float lumaMinM = min(lumaMin, rgbyM.w); + float lumaMaxM = max(lumaMax, rgbyM.w); + #else + float lumaMinM = min(lumaMin, rgbyM.y); + float lumaMaxM = max(lumaMax, rgbyM.y); + #endif + if((lumaMaxM - lumaMinM) < max(fxaaConsoleEdgeThresholdMin, lumaMax * fxaaConsoleEdgeThreshold)) return rgbyM; +/*--------------------------------------------------------------------------*/ + float2 dir; + dir.x = dot(lumaNwNeSwSe, fxaaConsole360ConstDir.yyxx); + dir.y = dot(lumaNwNeSwSe, fxaaConsole360ConstDir.xyxy); + dir = normalize(dir); +/*--------------------------------------------------------------------------*/ + float4 dir1 = dir.xyxy * fxaaConsoleRcpFrameOpt.xyzw; +/*--------------------------------------------------------------------------*/ + float4 dir2; + float dirAbsMinTimesC = min(abs(dir.x), abs(dir.y)) * fxaaConsoleEdgeSharpness; + dir2 = saturate(fxaaConsole360ConstDir.zzww * dir.xyxy / dirAbsMinTimesC + 0.5); + dir2 = dir2 * fxaaConsole360RcpFrameOpt2.xyxy + fxaaConsole360RcpFrameOpt2.zwzw; +/*--------------------------------------------------------------------------*/ + float4 rgbyN1 = tex2Dlod(fxaaConsole360TexExpBiasNegOne, float4(pos.xy + dir1.xy, 0.0, 0.0)); + float4 rgbyP1 = tex2Dlod(fxaaConsole360TexExpBiasNegOne, float4(pos.xy + dir1.zw, 0.0, 0.0)); + float4 rgbyN2 = tex2Dlod(fxaaConsole360TexExpBiasNegTwo, float4(pos.xy + dir2.xy, 0.0, 0.0)); + float4 rgbyP2 = tex2Dlod(fxaaConsole360TexExpBiasNegTwo, float4(pos.xy + dir2.zw, 0.0, 0.0)); +/*--------------------------------------------------------------------------*/ + float4 rgbyA = rgbyN1 + rgbyP1; + float4 rgbyB = rgbyN2 + rgbyP2 + rgbyA * 0.5; +/*--------------------------------------------------------------------------*/ + float4 rgbyR = ((FxaaLuma(rgbyB) - lumaMax) > 0.0) ? rgbyA : rgbyB; + rgbyR = ((FxaaLuma(rgbyB) - lumaMin) > 0.0) ? rgbyR : rgbyA; + return rgbyR; } +/*==========================================================================*/ +#endif + + + +/*============================================================================ + + FXAA3 CONSOLE - OPTIMIZED PS3 PIXEL SHADER (NO EARLY EXIT) + +============================================================================== +The code below does not exactly match the assembly. +I have a feeling that 12 cycles is possible, but was not able to get there. +Might have to increase register count to get full performance. +Note this shader does not use perspective interpolation. + +Use the following cgc options, + + --fenable-bx2 --fastmath --fastprecision --nofloatbindings + +------------------------------------------------------------------------------ + NVSHADERPERF OUTPUT +------------------------------------------------------------------------------ +For reference and to aid in debug, output of NVShaderPerf should match this, + +Shader to schedule: + 0: texpkb h0.w(TRUE), v5.zyxx, #0 + 2: addh h2.z(TRUE), h0.w, constant(0.001953, 0.000000, 0.000000, 0.000000).x + 4: texpkb h0.w(TRUE), v5.xwxx, #0 + 6: addh h0.z(TRUE), -h2, h0.w + 7: texpkb h1.w(TRUE), v5, #0 + 9: addh h0.x(TRUE), h0.z, -h1.w + 10: addh h3.w(TRUE), h0.z, h1 + 11: texpkb h2.w(TRUE), v5.zwzz, #0 + 13: addh h0.z(TRUE), h3.w, -h2.w + 14: addh h0.x(TRUE), h2.w, h0 + 15: nrmh h1.xz(TRUE), h0_n + 16: minh_m8 h0.x(TRUE), |h1|, |h1.z| + 17: maxh h4.w(TRUE), h0, h1 + 18: divx h2.xy(TRUE), h1_n.xzzw, h0_n + 19: movr r1.zw(TRUE), v4.xxxy + 20: madr r2.xz(TRUE), -h1, constant(cConst5.x, cConst5.y, cConst5.z, cConst5.w).zzww, r1.zzww + 22: minh h5.w(TRUE), h0, h1 + 23: texpkb h0(TRUE), r2.xzxx, #0 + 25: madr r0.zw(TRUE), h1.xzxz, constant(cConst5.x, cConst5.y, cConst5.z, cConst5.w), r1 + 27: maxh h4.x(TRUE), h2.z, h2.w + 28: texpkb h1(TRUE), r0.zwzz, #0 + 30: addh_d2 h1(TRUE), h0, h1 + 31: madr r0.xy(TRUE), -h2, constant(cConst5.x, cConst5.y, cConst5.z, cConst5.w).xyxx, r1.zwzz + 33: texpkb h0(TRUE), r0, #0 + 35: minh h4.z(TRUE), h2, h2.w + 36: fenct TRUE + 37: madr r1.xy(TRUE), h2, constant(cConst5.x, cConst5.y, cConst5.z, cConst5.w).xyxx, r1.zwzz + 39: texpkb h2(TRUE), r1, #0 + 41: addh_d2 h0(TRUE), h0, h2 + 42: maxh h2.w(TRUE), h4, h4.x + 43: minh h2.x(TRUE), h5.w, h4.z + 44: addh_d2 h0(TRUE), h0, h1 + 45: slth h2.x(TRUE), h0.w, h2 + 46: sgth h2.w(TRUE), h0, h2 + 47: movh h0(TRUE), h0 + 48: addx.c0 rc(TRUE), h2, h2.w + 49: movh h0(c0.NE.x), h1 + +IPU0 ------ Simplified schedule: -------- +Pass | Unit | uOp | PC: Op +-----+--------+------+------------------------- + 1 | SCT0/1 | mov | 0: TXLr h0.w, g[TEX1].zyxx, const.xxxx, TEX0; + | TEX | txl | 0: TXLr h0.w, g[TEX1].zyxx, const.xxxx, TEX0; + | SCB1 | add | 2: ADDh h2.z, h0.--w-, const.--x-; + | | | + 2 | SCT0/1 | mov | 4: TXLr h0.w, g[TEX1].xwxx, const.xxxx, TEX0; + | TEX | txl | 4: TXLr h0.w, g[TEX1].xwxx, const.xxxx, TEX0; + | SCB1 | add | 6: ADDh h0.z,-h2, h0.--w-; + | | | + 3 | SCT0/1 | mov | 7: TXLr h1.w, g[TEX1], const.xxxx, TEX0; + | TEX | txl | 7: TXLr h1.w, g[TEX1], const.xxxx, TEX0; + | SCB0 | add | 9: ADDh h0.x, h0.z---,-h1.w---; + | SCB1 | add | 10: ADDh h3.w, h0.---z, h1; + | | | + 4 | SCT0/1 | mov | 11: TXLr h2.w, g[TEX1].zwzz, const.xxxx, TEX0; + | TEX | txl | 11: TXLr h2.w, g[TEX1].zwzz, const.xxxx, TEX0; + | SCB0 | add | 14: ADDh h0.x, h2.w---, h0; + | SCB1 | add | 13: ADDh h0.z, h3.--w-,-h2.--w-; + | | | + 5 | SCT1 | mov | 15: NRMh h1.xz, h0; + | SRB | nrm | 15: NRMh h1.xz, h0; + | SCB0 | min | 16: MINh*8 h0.x, |h1|, |h1.z---|; + | SCB1 | max | 17: MAXh h4.w, h0, h1; + | | | + 6 | SCT0 | div | 18: DIVx h2.xy, h1.xz--, h0; + | SCT1 | mov | 19: MOVr r1.zw, g[TEX0].--xy; + | SCB0 | mad | 20: MADr r2.xz,-h1, const.z-w-, r1.z-w-; + | SCB1 | min | 22: MINh h5.w, h0, h1; + | | | + 7 | SCT0/1 | mov | 23: TXLr h0, r2.xzxx, const.xxxx, TEX0; + | TEX | txl | 23: TXLr h0, r2.xzxx, const.xxxx, TEX0; + | SCB0 | max | 27: MAXh h4.x, h2.z---, h2.w---; + | SCB1 | mad | 25: MADr r0.zw, h1.--xz, const, r1; + | | | + 8 | SCT0/1 | mov | 28: TXLr h1, r0.zwzz, const.xxxx, TEX0; + | TEX | txl | 28: TXLr h1, r0.zwzz, const.xxxx, TEX0; + | SCB0/1 | add | 30: ADDh/2 h1, h0, h1; + | | | + 9 | SCT0 | mad | 31: MADr r0.xy,-h2, const.xy--, r1.zw--; + | SCT1 | mov | 33: TXLr h0, r0, const.zzzz, TEX0; + | TEX | txl | 33: TXLr h0, r0, const.zzzz, TEX0; + | SCB1 | min | 35: MINh h4.z, h2, h2.--w-; + | | | + 10 | SCT0 | mad | 37: MADr r1.xy, h2, const.xy--, r1.zw--; + | SCT1 | mov | 39: TXLr h2, r1, const.zzzz, TEX0; + | TEX | txl | 39: TXLr h2, r1, const.zzzz, TEX0; + | SCB0/1 | add | 41: ADDh/2 h0, h0, h2; + | | | + 11 | SCT0 | min | 43: MINh h2.x, h5.w---, h4.z---; + | SCT1 | max | 42: MAXh h2.w, h4, h4.---x; + | SCB0/1 | add | 44: ADDh/2 h0, h0, h1; + | | | + 12 | SCT0 | set | 45: SLTh h2.x, h0.w---, h2; + | SCT1 | set | 46: SGTh h2.w, h0, h2; + | SCB0/1 | mul | 47: MOVh h0, h0; + | | | + 13 | SCT0 | mad | 48: ADDxc0_s rc, h2, h2.w---; + | SCB0/1 | mul | 49: MOVh h0(NE0.xxxx), h1; + +Pass SCT TEX SCB + 1: 0% 100% 25% + 2: 0% 100% 25% + 3: 0% 100% 50% + 4: 0% 100% 50% + 5: 0% 0% 50% + 6: 100% 0% 75% + 7: 0% 100% 75% + 8: 0% 100% 100% + 9: 0% 100% 25% + 10: 0% 100% 100% + 11: 50% 0% 100% + 12: 50% 0% 100% + 13: 25% 0% 100% + +MEAN: 17% 61% 67% + +Pass SCT0 SCT1 TEX SCB0 SCB1 + 1: 0% 0% 100% 0% 100% + 2: 0% 0% 100% 0% 100% + 3: 0% 0% 100% 100% 100% + 4: 0% 0% 100% 100% 100% + 5: 0% 0% 0% 100% 100% + 6: 100% 100% 0% 100% 100% + 7: 0% 0% 100% 100% 100% + 8: 0% 0% 100% 100% 100% + 9: 0% 0% 100% 0% 100% + 10: 0% 0% 100% 100% 100% + 11: 100% 100% 0% 100% 100% + 12: 100% 100% 0% 100% 100% + 13: 100% 0% 0% 100% 100% + +MEAN: 30% 23% 61% 76% 100% +Fragment Performance Setup: Driver RSX Compiler, GPU RSX, Flags 0x5 +Results 13 cycles, 3 r regs, 923,076,923 pixels/s +============================================================================*/ +#if (FXAA_PS3 == 1) && (FXAA_EARLY_EXIT == 0) +/*--------------------------------------------------------------------------*/ +#pragma regcount 7 +#pragma disablepc all +#pragma option O3 +#pragma option OutColorPrec=fp16 +#pragma texformat default RGBA8 +/*==========================================================================*/ +half4 FxaaPixelShader( + // See FXAA Quality FxaaPixelShader() source for docs on Inputs! + FxaaFloat2 pos, + FxaaFloat4 fxaaConsolePosPos, + FxaaTex tex, + FxaaTex fxaaConsole360TexExpBiasNegOne, + FxaaTex fxaaConsole360TexExpBiasNegTwo, + FxaaFloat2 fxaaQualityRcpFrame, + FxaaFloat4 fxaaConsoleRcpFrameOpt, + FxaaFloat4 fxaaConsoleRcpFrameOpt2, + FxaaFloat4 fxaaConsole360RcpFrameOpt2, + FxaaFloat fxaaQualitySubpix, + FxaaFloat fxaaQualityEdgeThreshold, + FxaaFloat fxaaQualityEdgeThresholdMin, + FxaaFloat fxaaConsoleEdgeSharpness, + FxaaFloat fxaaConsoleEdgeThreshold, + FxaaFloat fxaaConsoleEdgeThresholdMin, + FxaaFloat4 fxaaConsole360ConstDir +) { +/*--------------------------------------------------------------------------*/ +// (1) + half4 dir; + half4 lumaNe = h4tex2Dlod(tex, half4(fxaaConsolePosPos.zy, 0, 0)); + #if (FXAA_GREEN_AS_LUMA == 0) + lumaNe.w += half(1.0/512.0); + dir.x = -lumaNe.w; + dir.z = -lumaNe.w; + #else + lumaNe.y += half(1.0/512.0); + dir.x = -lumaNe.y; + dir.z = -lumaNe.y; + #endif +/*--------------------------------------------------------------------------*/ +// (2) + half4 lumaSw = h4tex2Dlod(tex, half4(fxaaConsolePosPos.xw, 0, 0)); + #if (FXAA_GREEN_AS_LUMA == 0) + dir.x += lumaSw.w; + dir.z += lumaSw.w; + #else + dir.x += lumaSw.y; + dir.z += lumaSw.y; + #endif +/*--------------------------------------------------------------------------*/ +// (3) + half4 lumaNw = h4tex2Dlod(tex, half4(fxaaConsolePosPos.xy, 0, 0)); + #if (FXAA_GREEN_AS_LUMA == 0) + dir.x -= lumaNw.w; + dir.z += lumaNw.w; + #else + dir.x -= lumaNw.y; + dir.z += lumaNw.y; + #endif +/*--------------------------------------------------------------------------*/ +// (4) + half4 lumaSe = h4tex2Dlod(tex, half4(fxaaConsolePosPos.zw, 0, 0)); + #if (FXAA_GREEN_AS_LUMA == 0) + dir.x += lumaSe.w; + dir.z -= lumaSe.w; + #else + dir.x += lumaSe.y; + dir.z -= lumaSe.y; + #endif +/*--------------------------------------------------------------------------*/ +// (5) + half4 dir1_pos; + dir1_pos.xy = normalize(dir.xyz).xz; + half dirAbsMinTimesC = min(abs(dir1_pos.x), abs(dir1_pos.y)) * half(FXAA_CONSOLE__PS3_EDGE_SHARPNESS); +/*--------------------------------------------------------------------------*/ +// (6) + half4 dir2_pos; + dir2_pos.xy = clamp(dir1_pos.xy / dirAbsMinTimesC, half(-2.0), half(2.0)); + dir1_pos.zw = pos.xy; + dir2_pos.zw = pos.xy; + half4 temp1N; + temp1N.xy = dir1_pos.zw - dir1_pos.xy * fxaaConsoleRcpFrameOpt.zw; +/*--------------------------------------------------------------------------*/ +// (7) + temp1N = h4tex2Dlod(tex, half4(temp1N.xy, 0.0, 0.0)); + half4 rgby1; + rgby1.xy = dir1_pos.zw + dir1_pos.xy * fxaaConsoleRcpFrameOpt.zw; +/*--------------------------------------------------------------------------*/ +// (8) + rgby1 = h4tex2Dlod(tex, half4(rgby1.xy, 0.0, 0.0)); + rgby1 = (temp1N + rgby1) * 0.5; +/*--------------------------------------------------------------------------*/ +// (9) + half4 temp2N; + temp2N.xy = dir2_pos.zw - dir2_pos.xy * fxaaConsoleRcpFrameOpt2.zw; + temp2N = h4tex2Dlod(tex, half4(temp2N.xy, 0.0, 0.0)); +/*--------------------------------------------------------------------------*/ +// (10) + half4 rgby2; + rgby2.xy = dir2_pos.zw + dir2_pos.xy * fxaaConsoleRcpFrameOpt2.zw; + rgby2 = h4tex2Dlod(tex, half4(rgby2.xy, 0.0, 0.0)); + rgby2 = (temp2N + rgby2) * 0.5; +/*--------------------------------------------------------------------------*/ +// (11) + // compilier moves these scalar ops up to other cycles + #if (FXAA_GREEN_AS_LUMA == 0) + half lumaMin = min(min(lumaNw.w, lumaSw.w), min(lumaNe.w, lumaSe.w)); + half lumaMax = max(max(lumaNw.w, lumaSw.w), max(lumaNe.w, lumaSe.w)); + #else + half lumaMin = min(min(lumaNw.y, lumaSw.y), min(lumaNe.y, lumaSe.y)); + half lumaMax = max(max(lumaNw.y, lumaSw.y), max(lumaNe.y, lumaSe.y)); + #endif + rgby2 = (rgby2 + rgby1) * 0.5; +/*--------------------------------------------------------------------------*/ +// (12) + #if (FXAA_GREEN_AS_LUMA == 0) + bool twoTapLt = rgby2.w < lumaMin; + bool twoTapGt = rgby2.w > lumaMax; + #else + bool twoTapLt = rgby2.y < lumaMin; + bool twoTapGt = rgby2.y > lumaMax; + #endif +/*--------------------------------------------------------------------------*/ +// (13) + if(twoTapLt || twoTapGt) rgby2 = rgby1; +/*--------------------------------------------------------------------------*/ + return rgby2; } +/*==========================================================================*/ +#endif + + + +/*============================================================================ + + FXAA3 CONSOLE - OPTIMIZED PS3 PIXEL SHADER (WITH EARLY EXIT) + +============================================================================== +The code mostly matches the assembly. +I have a feeling that 14 cycles is possible, but was not able to get there. +Might have to increase register count to get full performance. +Note this shader does not use perspective interpolation. + +Use the following cgc options, + + --fenable-bx2 --fastmath --fastprecision --nofloatbindings + +Use of FXAA_GREEN_AS_LUMA currently adds a cycle (16 clks). +Will look at fixing this for FXAA 3.12. +------------------------------------------------------------------------------ + NVSHADERPERF OUTPUT +------------------------------------------------------------------------------ +For reference and to aid in debug, output of NVShaderPerf should match this, + +Shader to schedule: + 0: texpkb h0.w(TRUE), v5.zyxx, #0 + 2: addh h2.y(TRUE), h0.w, constant(0.001953, 0.000000, 0.000000, 0.000000).x + 4: texpkb h1.w(TRUE), v5.xwxx, #0 + 6: addh h0.x(TRUE), h1.w, -h2.y + 7: texpkb h2.w(TRUE), v5.zwzz, #0 + 9: minh h4.w(TRUE), h2.y, h2 + 10: maxh h5.x(TRUE), h2.y, h2.w + 11: texpkb h0.w(TRUE), v5, #0 + 13: addh h3.w(TRUE), -h0, h0.x + 14: addh h0.x(TRUE), h0.w, h0 + 15: addh h0.z(TRUE), -h2.w, h0.x + 16: addh h0.x(TRUE), h2.w, h3.w + 17: minh h5.y(TRUE), h0.w, h1.w + 18: nrmh h2.xz(TRUE), h0_n + 19: minh_m8 h2.w(TRUE), |h2.x|, |h2.z| + 20: divx h4.xy(TRUE), h2_n.xzzw, h2_n.w + 21: movr r1.zw(TRUE), v4.xxxy + 22: maxh h2.w(TRUE), h0, h1 + 23: fenct TRUE + 24: madr r0.xy(TRUE), -h2.xzzw, constant(cConst5.x, cConst5.y, cConst5.z, cConst5.w).zwzz, r1.zwzz + 26: texpkb h0(TRUE), r0, #0 + 28: maxh h5.x(TRUE), h2.w, h5 + 29: minh h5.w(TRUE), h5.y, h4 + 30: madr r1.xy(TRUE), h2.xzzw, constant(cConst5.x, cConst5.y, cConst5.z, cConst5.w).zwzz, r1.zwzz + 32: texpkb h2(TRUE), r1, #0 + 34: addh_d2 h2(TRUE), h0, h2 + 35: texpkb h1(TRUE), v4, #0 + 37: maxh h5.y(TRUE), h5.x, h1.w + 38: minh h4.w(TRUE), h1, h5 + 39: madr r0.xy(TRUE), -h4, constant(cConst5.x, cConst5.y, cConst5.z, cConst5.w).xyxx, r1.zwzz + 41: texpkb h0(TRUE), r0, #0 + 43: addh_m8 h5.z(TRUE), h5.y, -h4.w + 44: madr r2.xy(TRUE), h4, constant(cConst5.x, cConst5.y, cConst5.z, cConst5.w).xyxx, r1.zwzz + 46: texpkb h3(TRUE), r2, #0 + 48: addh_d2 h0(TRUE), h0, h3 + 49: addh_d2 h3(TRUE), h0, h2 + 50: movh h0(TRUE), h3 + 51: slth h3.x(TRUE), h3.w, h5.w + 52: sgth h3.w(TRUE), h3, h5.x + 53: addx.c0 rc(TRUE), h3.x, h3 + 54: slth.c0 rc(TRUE), h5.z, h5 + 55: movh h0(c0.NE.w), h2 + 56: movh h0(c0.NE.x), h1 + +IPU0 ------ Simplified schedule: -------- +Pass | Unit | uOp | PC: Op +-----+--------+------+------------------------- + 1 | SCT0/1 | mov | 0: TXLr h0.w, g[TEX1].zyxx, const.xxxx, TEX0; + | TEX | txl | 0: TXLr h0.w, g[TEX1].zyxx, const.xxxx, TEX0; + | SCB0 | add | 2: ADDh h2.y, h0.-w--, const.-x--; + | | | + 2 | SCT0/1 | mov | 4: TXLr h1.w, g[TEX1].xwxx, const.xxxx, TEX0; + | TEX | txl | 4: TXLr h1.w, g[TEX1].xwxx, const.xxxx, TEX0; + | SCB0 | add | 6: ADDh h0.x, h1.w---,-h2.y---; + | | | + 3 | SCT0/1 | mov | 7: TXLr h2.w, g[TEX1].zwzz, const.xxxx, TEX0; + | TEX | txl | 7: TXLr h2.w, g[TEX1].zwzz, const.xxxx, TEX0; + | SCB0 | max | 10: MAXh h5.x, h2.y---, h2.w---; + | SCB1 | min | 9: MINh h4.w, h2.---y, h2; + | | | + 4 | SCT0/1 | mov | 11: TXLr h0.w, g[TEX1], const.xxxx, TEX0; + | TEX | txl | 11: TXLr h0.w, g[TEX1], const.xxxx, TEX0; + | SCB0 | add | 14: ADDh h0.x, h0.w---, h0; + | SCB1 | add | 13: ADDh h3.w,-h0, h0.---x; + | | | + 5 | SCT0 | mad | 16: ADDh h0.x, h2.w---, h3.w---; + | SCT1 | mad | 15: ADDh h0.z,-h2.--w-, h0.--x-; + | SCB0 | min | 17: MINh h5.y, h0.-w--, h1.-w--; + | | | + 6 | SCT1 | mov | 18: NRMh h2.xz, h0; + | SRB | nrm | 18: NRMh h2.xz, h0; + | SCB1 | min | 19: MINh*8 h2.w, |h2.---x|, |h2.---z|; + | | | + 7 | SCT0 | div | 20: DIVx h4.xy, h2.xz--, h2.ww--; + | SCT1 | mov | 21: MOVr r1.zw, g[TEX0].--xy; + | SCB1 | max | 22: MAXh h2.w, h0, h1; + | | | + 8 | SCT0 | mad | 24: MADr r0.xy,-h2.xz--, const.zw--, r1.zw--; + | SCT1 | mov | 26: TXLr h0, r0, const.xxxx, TEX0; + | TEX | txl | 26: TXLr h0, r0, const.xxxx, TEX0; + | SCB0 | max | 28: MAXh h5.x, h2.w---, h5; + | SCB1 | min | 29: MINh h5.w, h5.---y, h4; + | | | + 9 | SCT0 | mad | 30: MADr r1.xy, h2.xz--, const.zw--, r1.zw--; + | SCT1 | mov | 32: TXLr h2, r1, const.xxxx, TEX0; + | TEX | txl | 32: TXLr h2, r1, const.xxxx, TEX0; + | SCB0/1 | add | 34: ADDh/2 h2, h0, h2; + | | | + 10 | SCT0/1 | mov | 35: TXLr h1, g[TEX0], const.xxxx, TEX0; + | TEX | txl | 35: TXLr h1, g[TEX0], const.xxxx, TEX0; + | SCB0 | max | 37: MAXh h5.y, h5.-x--, h1.-w--; + | SCB1 | min | 38: MINh h4.w, h1, h5; + | | | + 11 | SCT0 | mad | 39: MADr r0.xy,-h4, const.xy--, r1.zw--; + | SCT1 | mov | 41: TXLr h0, r0, const.zzzz, TEX0; + | TEX | txl | 41: TXLr h0, r0, const.zzzz, TEX0; + | SCB0 | mad | 44: MADr r2.xy, h4, const.xy--, r1.zw--; + | SCB1 | add | 43: ADDh*8 h5.z, h5.--y-,-h4.--w-; + | | | + 12 | SCT0/1 | mov | 46: TXLr h3, r2, const.xxxx, TEX0; + | TEX | txl | 46: TXLr h3, r2, const.xxxx, TEX0; + | SCB0/1 | add | 48: ADDh/2 h0, h0, h3; + | | | + 13 | SCT0/1 | mad | 49: ADDh/2 h3, h0, h2; + | SCB0/1 | mul | 50: MOVh h0, h3; + | | | + 14 | SCT0 | set | 51: SLTh h3.x, h3.w---, h5.w---; + | SCT1 | set | 52: SGTh h3.w, h3, h5.---x; + | SCB0 | set | 54: SLThc0 rc, h5.z---, h5; + | SCB1 | add | 53: ADDxc0_s rc, h3.---x, h3; + | | | + 15 | SCT0/1 | mul | 55: MOVh h0(NE0.wwww), h2; + | SCB0/1 | mul | 56: MOVh h0(NE0.xxxx), h1; + +Pass SCT TEX SCB + 1: 0% 100% 25% + 2: 0% 100% 25% + 3: 0% 100% 50% + 4: 0% 100% 50% + 5: 50% 0% 25% + 6: 0% 0% 25% + 7: 100% 0% 25% + 8: 0% 100% 50% + 9: 0% 100% 100% + 10: 0% 100% 50% + 11: 0% 100% 75% + 12: 0% 100% 100% + 13: 100% 0% 100% + 14: 50% 0% 50% + 15: 100% 0% 100% + +MEAN: 26% 60% 56% + +Pass SCT0 SCT1 TEX SCB0 SCB1 + 1: 0% 0% 100% 100% 0% + 2: 0% 0% 100% 100% 0% + 3: 0% 0% 100% 100% 100% + 4: 0% 0% 100% 100% 100% + 5: 100% 100% 0% 100% 0% + 6: 0% 0% 0% 0% 100% + 7: 100% 100% 0% 0% 100% + 8: 0% 0% 100% 100% 100% + 9: 0% 0% 100% 100% 100% + 10: 0% 0% 100% 100% 100% + 11: 0% 0% 100% 100% 100% + 12: 0% 0% 100% 100% 100% + 13: 100% 100% 0% 100% 100% + 14: 100% 100% 0% 100% 100% + 15: 100% 100% 0% 100% 100% + +MEAN: 33% 33% 60% 86% 80% +Fragment Performance Setup: Driver RSX Compiler, GPU RSX, Flags 0x5 +Results 15 cycles, 3 r regs, 800,000,000 pixels/s +============================================================================*/ +#if (FXAA_PS3 == 1) && (FXAA_EARLY_EXIT == 1) +/*--------------------------------------------------------------------------*/ +#pragma regcount 7 +#pragma disablepc all +#pragma option O2 +#pragma option OutColorPrec=fp16 +#pragma texformat default RGBA8 +/*==========================================================================*/ +half4 FxaaPixelShader( + // See FXAA Quality FxaaPixelShader() source for docs on Inputs! + FxaaFloat2 pos, + FxaaFloat4 fxaaConsolePosPos, + FxaaTex tex, + FxaaTex fxaaConsole360TexExpBiasNegOne, + FxaaTex fxaaConsole360TexExpBiasNegTwo, + FxaaFloat2 fxaaQualityRcpFrame, + FxaaFloat4 fxaaConsoleRcpFrameOpt, + FxaaFloat4 fxaaConsoleRcpFrameOpt2, + FxaaFloat4 fxaaConsole360RcpFrameOpt2, + FxaaFloat fxaaQualitySubpix, + FxaaFloat fxaaQualityEdgeThreshold, + FxaaFloat fxaaQualityEdgeThresholdMin, + FxaaFloat fxaaConsoleEdgeSharpness, + FxaaFloat fxaaConsoleEdgeThreshold, + FxaaFloat fxaaConsoleEdgeThresholdMin, + FxaaFloat4 fxaaConsole360ConstDir +) { +/*--------------------------------------------------------------------------*/ +// (1) + half4 rgbyNe = h4tex2Dlod(tex, half4(fxaaConsolePosPos.zy, 0, 0)); + #if (FXAA_GREEN_AS_LUMA == 0) + half lumaNe = rgbyNe.w + half(1.0/512.0); + #else + half lumaNe = rgbyNe.y + half(1.0/512.0); + #endif +/*--------------------------------------------------------------------------*/ +// (2) + half4 lumaSw = h4tex2Dlod(tex, half4(fxaaConsolePosPos.xw, 0, 0)); + #if (FXAA_GREEN_AS_LUMA == 0) + half lumaSwNegNe = lumaSw.w - lumaNe; + #else + half lumaSwNegNe = lumaSw.y - lumaNe; + #endif +/*--------------------------------------------------------------------------*/ +// (3) + half4 lumaNw = h4tex2Dlod(tex, half4(fxaaConsolePosPos.xy, 0, 0)); + #if (FXAA_GREEN_AS_LUMA == 0) + half lumaMaxNwSw = max(lumaNw.w, lumaSw.w); + half lumaMinNwSw = min(lumaNw.w, lumaSw.w); + #else + half lumaMaxNwSw = max(lumaNw.y, lumaSw.y); + half lumaMinNwSw = min(lumaNw.y, lumaSw.y); + #endif +/*--------------------------------------------------------------------------*/ +// (4) + half4 lumaSe = h4tex2Dlod(tex, half4(fxaaConsolePosPos.zw, 0, 0)); + #if (FXAA_GREEN_AS_LUMA == 0) + half dirZ = lumaNw.w + lumaSwNegNe; + half dirX = -lumaNw.w + lumaSwNegNe; + #else + half dirZ = lumaNw.y + lumaSwNegNe; + half dirX = -lumaNw.y + lumaSwNegNe; + #endif +/*--------------------------------------------------------------------------*/ +// (5) + half3 dir; + dir.y = 0.0; + #if (FXAA_GREEN_AS_LUMA == 0) + dir.x = lumaSe.w + dirX; + dir.z = -lumaSe.w + dirZ; + half lumaMinNeSe = min(lumaNe, lumaSe.w); + #else + dir.x = lumaSe.y + dirX; + dir.z = -lumaSe.y + dirZ; + half lumaMinNeSe = min(lumaNe, lumaSe.y); + #endif +/*--------------------------------------------------------------------------*/ +// (6) + half4 dir1_pos; + dir1_pos.xy = normalize(dir).xz; + half dirAbsMinTimes8 = min(abs(dir1_pos.x), abs(dir1_pos.y)) * half(FXAA_CONSOLE__PS3_EDGE_SHARPNESS); +/*--------------------------------------------------------------------------*/ +// (7) + half4 dir2_pos; + dir2_pos.xy = clamp(dir1_pos.xy / dirAbsMinTimes8, half(-2.0), half(2.0)); + dir1_pos.zw = pos.xy; + dir2_pos.zw = pos.xy; + #if (FXAA_GREEN_AS_LUMA == 0) + half lumaMaxNeSe = max(lumaNe, lumaSe.w); + #else + half lumaMaxNeSe = max(lumaNe, lumaSe.y); + #endif +/*--------------------------------------------------------------------------*/ +// (8) + half4 temp1N; + temp1N.xy = dir1_pos.zw - dir1_pos.xy * fxaaConsoleRcpFrameOpt.zw; + temp1N = h4tex2Dlod(tex, half4(temp1N.xy, 0.0, 0.0)); + half lumaMax = max(lumaMaxNwSw, lumaMaxNeSe); + half lumaMin = min(lumaMinNwSw, lumaMinNeSe); +/*--------------------------------------------------------------------------*/ +// (9) + half4 rgby1; + rgby1.xy = dir1_pos.zw + dir1_pos.xy * fxaaConsoleRcpFrameOpt.zw; + rgby1 = h4tex2Dlod(tex, half4(rgby1.xy, 0.0, 0.0)); + rgby1 = (temp1N + rgby1) * 0.5; +/*--------------------------------------------------------------------------*/ +// (10) + half4 rgbyM = h4tex2Dlod(tex, half4(pos.xy, 0.0, 0.0)); + #if (FXAA_GREEN_AS_LUMA == 0) + half lumaMaxM = max(lumaMax, rgbyM.w); + half lumaMinM = min(lumaMin, rgbyM.w); + #else + half lumaMaxM = max(lumaMax, rgbyM.y); + half lumaMinM = min(lumaMin, rgbyM.y); + #endif +/*--------------------------------------------------------------------------*/ +// (11) + half4 temp2N; + temp2N.xy = dir2_pos.zw - dir2_pos.xy * fxaaConsoleRcpFrameOpt2.zw; + temp2N = h4tex2Dlod(tex, half4(temp2N.xy, 0.0, 0.0)); + half4 rgby2; + rgby2.xy = dir2_pos.zw + dir2_pos.xy * fxaaConsoleRcpFrameOpt2.zw; + half lumaRangeM = (lumaMaxM - lumaMinM) / FXAA_CONSOLE__PS3_EDGE_THRESHOLD; +/*--------------------------------------------------------------------------*/ +// (12) + rgby2 = h4tex2Dlod(tex, half4(rgby2.xy, 0.0, 0.0)); + rgby2 = (temp2N + rgby2) * 0.5; +/*--------------------------------------------------------------------------*/ +// (13) + rgby2 = (rgby2 + rgby1) * 0.5; +/*--------------------------------------------------------------------------*/ +// (14) + #if (FXAA_GREEN_AS_LUMA == 0) + bool twoTapLt = rgby2.w < lumaMin; + bool twoTapGt = rgby2.w > lumaMax; + #else + bool twoTapLt = rgby2.y < lumaMin; + bool twoTapGt = rgby2.y > lumaMax; + #endif + bool earlyExit = lumaRangeM < lumaMax; + bool twoTap = twoTapLt || twoTapGt; +/*--------------------------------------------------------------------------*/ +// (15) + if(twoTap) rgby2 = rgby1; + if(earlyExit) rgby2 = rgbyM; +/*--------------------------------------------------------------------------*/ + return rgby2; } +/*==========================================================================*/ +#endif diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/FXAA/Resources/FXAA3.cginc.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/FXAA/Resources/FXAA3.cginc.meta new file mode 100644 index 0000000..2c82c38 --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/FXAA/Resources/FXAA3.cginc.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: b44d2ca11a7157e4db9f1e02f5249f95 +timeCreated: 1453990603 +licenseType: Store +ShaderImporter: + defaultTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/IAntiAliasing.cs b/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/IAntiAliasing.cs new file mode 100644 index 0000000..3b77d2a --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/IAntiAliasing.cs @@ -0,0 +1,13 @@ +using UnityEngine; + +namespace UnityStandardAssets.CinematicEffects +{ + public interface IAntiAliasing + { + void OnEnable(AntiAliasing owner); + void OnDisable(); + void OnPreCull(Camera camera); + void OnPostRender(Camera camera); + void OnRenderImage(Camera camera, RenderTexture source, RenderTexture destination); + } +} diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/IAntiAliasing.cs.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/IAntiAliasing.cs.meta new file mode 100644 index 0000000..b2b8673 --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/IAntiAliasing.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 90329fa7c7a616243a47de84e6e5c041 +timeCreated: 1454590083 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/SMAA.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/SMAA.meta new file mode 100644 index 0000000..a9141f0 --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/SMAA.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: d958f8498dd28db459dc41b661331fc8 +folderAsset: yes +timeCreated: 1446717353 +licenseType: Store +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/SMAA/Editor.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/SMAA/Editor.meta new file mode 100644 index 0000000..3b2a057 --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/SMAA/Editor.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 3ab9eab0d04085b4abd47b6b0657143c +folderAsset: yes +timeCreated: 1430588699 +licenseType: Store +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/SMAA/Editor/SMAAEditor.cs b/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/SMAA/Editor/SMAAEditor.cs new file mode 100644 index 0000000..24a4ce7 --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/SMAA/Editor/SMAAEditor.cs @@ -0,0 +1,106 @@ +using UnityEditor; +using System.Collections.Generic; +using System; +using System.Linq; +using UnityEngine; +using System.Reflection; +using UnityEngine.Serialization; + +namespace UnityStandardAssets.CinematicEffects +{ + public class SMAAEditor : IAntiAliasingEditor + { + private List m_TopLevelFields = new List(); + + [Serializable] + class InfoMap + { + public string name; + public bool experimental; + public bool quality; + public List properties; + } + private List m_GroupFields = new List(); + + public void OnEnable(SerializedObject serializedObject, string path) + { + var topLevelSettings = typeof(SMAA).GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance).Where(x => x.GetCustomAttributes(typeof(SMAA.TopLevelSettings), false).Any()); + var settingsGroups = typeof(SMAA).GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance).Where(x => x.GetCustomAttributes(typeof(SMAA.SettingsGroup), false).Any()); + + foreach (var group in topLevelSettings) + { + var searchPath = path + "." + group.Name + "."; + + foreach (var setting in group.FieldType.GetFields(BindingFlags.Instance | BindingFlags.Public)) + { + var property = serializedObject.FindProperty(searchPath + setting.Name); + if (property != null) + m_TopLevelFields.Add(property); + } + } + + foreach (var group in settingsGroups) + { + var searchPath = path + "." + group.Name + "."; + + foreach (var setting in group.FieldType.GetFields(BindingFlags.Instance | BindingFlags.Public)) + { + var infoGroup = m_GroupFields.FirstOrDefault(x => x.name == group.Name); + if (infoGroup == null) + { + infoGroup = new InfoMap(); + infoGroup.properties = new List(); + infoGroup.name = group.Name; + infoGroup.quality = group.FieldType == typeof(SMAA.QualitySettings); + infoGroup.experimental = group.GetCustomAttributes(typeof(SMAA.ExperimentalGroup), false).Length > 0; + m_GroupFields.Add(infoGroup); + } + + var property = serializedObject.FindProperty(searchPath + setting.Name); + if (property != null) + { + infoGroup.properties.Add(property); + } + } + } + } + + public bool OnInspectorGUI(IAntiAliasing target) + { + EditorGUI.BeginChangeCheck(); + + foreach (var setting in m_TopLevelFields) + EditorGUILayout.PropertyField(setting); + + foreach (var group in m_GroupFields) + { + if (group.quality && (target as SMAA).settings.quality != SMAA.QualityPreset.Custom) + { + continue; + } + + string title = ObjectNames.NicifyVariableName(group.name); + if (group.experimental) + title += " (Experimental)"; + + EditorGUILayout.Space(); + EditorGUILayout.LabelField(title, EditorStyles.boldLabel); + EditorGUI.indentLevel++; + + var enabledField = group.properties.FirstOrDefault(x => x.propertyPath == "m_SMAA." + group.name + ".enabled"); + if (enabledField != null && !enabledField.boolValue) + { + EditorGUILayout.PropertyField(enabledField); + EditorGUI.indentLevel--; + continue; + } + + foreach (var field in group.properties) + EditorGUILayout.PropertyField(field); + + EditorGUI.indentLevel--; + } + return EditorGUI.EndChangeCheck(); + } + } +} diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/SMAA/Editor/SMAAEditor.cs.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/SMAA/Editor/SMAAEditor.cs.meta new file mode 100644 index 0000000..c1ca0f6 --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/SMAA/Editor/SMAAEditor.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 5c2ffc06b5a6ee64d8e1d9bdf074732c +timeCreated: 1430643832 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/SMAA/Resources.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/SMAA/Resources.meta new file mode 100644 index 0000000..9f4930c --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/SMAA/Resources.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 9362798305520c448b294dd314a7daff +folderAsset: yes +timeCreated: 1430505545 +licenseType: Store +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/SMAA/Resources/AreaTex.tga b/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/SMAA/Resources/AreaTex.tga new file mode 100644 index 0000000000000000000000000000000000000000..57f595e65ec6397d7ee1636cae0920f9a1a152b4 GIT binary patch literal 358444 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
h1Ji3Vk;6Teu$M5X{{{Y%Ifyl& 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 literal 0 HcmV?d00001 diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/SMAA/Resources/AreaTex.tga.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/SMAA/Resources/AreaTex.tga.meta new file mode 100644 index 0000000..4938aed --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/SMAA/Resources/AreaTex.tga.meta @@ -0,0 +1,57 @@ +fileFormatVersion: 2 +guid: e62aa7035ea66c94b90b2d8774d02cca +timeCreated: 1432601000 +licenseType: Store +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + linearTexture: 1 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + cubemapConvolution: 0 + cubemapConvolutionSteps: 8 + cubemapConvolutionExponent: 1.5 + seamlessCubemap: 0 + textureFormat: -3 + maxTextureSize: 2048 + textureSettings: + filterMode: 1 + aniso: 0 + mipBias: -1 + wrapMode: 1 + nPOTScale: 0 + lightmap: 0 + rGBM: 2 + compressionQuality: 50 + allowsAlphaSplitting: 0 + 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 + alphaIsTransparency: 0 + textureType: 5 + buildTargetSettings: [] + spriteSheet: + sprites: [] + outline: [] + spritePackingTag: + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/SMAA/Resources/SMAA.cginc b/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/SMAA/Resources/SMAA.cginc new file mode 100644 index 0000000..1d271b0 --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/SMAA/Resources/SMAA.cginc @@ -0,0 +1,1433 @@ +// Ported to Unity by Thomas Hourdel (thomas.hourdel@gmail.com) + +/** + * Copyright (C) 2013 Jorge Jimenez (jorge@iryoku.com) + * Copyright (C) 2013 Jose I. Echevarria (joseignacioechevarria@gmail.com) + * Copyright (C) 2013 Belen Masia (bmasia@unizar.es) + * Copyright (C) 2013 Fernando Navarro (fernandn@microsoft.com) + * Copyright (C) 2013 Diego Gutierrez (diegog@unizar.es) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * 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. As clarification, there + * is no requirement that the copyright notice and permission be included in + * binary distributions 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. + */ + + +/** + * _______ ___ ___ ___ ___ + * / || \/ | / \ / \ + * | (---- | \ / | / ^ \ / ^ \ + * \ \ | |\/| | / /_\ \ / /_\ \ + * ----) | | | | | / _____ \ / _____ \ + * |_______/ |__| |__| /__/ \__\ /__/ \__\ + * + * E N H A N C E D + * S U B P I X E L M O R P H O L O G I C A L A N T I A L I A S I N G + * + * http://www.iryoku.com/smaa/ + * + * Hi, welcome aboard! + * + * Here you'll find instructions to get the shader up and running as fast as + * possible. + * + * IMPORTANTE NOTICE: when updating, remember to update both this file and the + * precomputed textures! They may change from version to version. + * + * The shader has three passes, chained together as follows: + * + * |input|------------------· + * v | + * [ SMAA*EdgeDetection ] | + * v | + * |edgesTex| | + * v | + * [ SMAABlendingWeightCalculation ] | + * v | + * |blendTex| | + * v | + * [ SMAANeighborhoodBlending ] <------· + * v + * |output| + * + * Note that each [pass] has its own vertex and pixel shader. Remember to use + * oversized triangles instead of quads to avoid overshading along the + * diagonal. + * + * You've three edge detection methods to choose from: luma, color or depth. + * They represent different quality/performance and anti-aliasing/sharpness + * tradeoffs, so our recommendation is for you to choose the one that best + * suits your particular scenario: + * + * - Depth edge detection is usually the fastest but it may miss some edges. + * + * - Luma edge detection is usually more expensive than depth edge detection, + * but catches visible edges that depth edge detection can miss. + * + * - Color edge detection is usually the most expensive one but catches + * chroma-only edges. + * + * For quickstarters: just use luma edge detection. + * + * The general advice is to not rush the integration process and ensure each + * step is done correctly (don't try to integrate SMAA T2x with predicated edge + * detection from the start!). Ok then, let's go! + * + * 1. The first step is to create two RGBA temporal render targets for holding + * |edgesTex| and |blendTex|. + * + * In DX10 or DX11, you can use a RG render target for the edges texture. + * In the case of NVIDIA GPUs, using RG render targets seems to actually be + * slower. + * + * On the Xbox 360, you can use the same render target for resolving both + * |edgesTex| and |blendTex|, as they aren't needed simultaneously. + * + * 2. Both temporal render targets |edgesTex| and |blendTex| must be cleared + * each frame. Do not forget to clear the alpha channel! + * + * 3. The next step is loading the two supporting precalculated textures, + * 'areaTex' and 'searchTex'. You'll find them in the 'Textures' folder as + * C++ headers, and also as regular DDS files. They'll be needed for the + * 'SMAABlendingWeightCalculation' pass. + * + * If you use the C++ headers, be sure to load them in the format specified + * inside of them. + * + * You can also compress 'areaTex' and 'searchTex' using BC5 and BC4 + * respectively, if you have that option in your content processor pipeline. + * When compressing then, you get a non-perceptible quality decrease, and a + * marginal performance increase. + * + * 4. All samplers must be set to linear filtering and clamp. + * + * After you get the technique working, remember that 64-bit inputs have + * half-rate linear filtering on GCN. + * + * If SMAA is applied to 64-bit color buffers, switching to point filtering + * when accesing them will increase the performance. Search for + * 'SMAASamplePoint' to see which textures may benefit from point + * filtering, and where (which is basically the color input in the edge + * detection and resolve passes). + * + * 5. All texture reads and buffer writes must be non-sRGB, with the exception + * of the input read and the output write in + * 'SMAANeighborhoodBlending' (and only in this pass!). If sRGB reads in + * this last pass are not possible, the technique will work anyway, but + * will perform antialiasing in gamma space. + * + * IMPORTANT: for best results the input read for the color/luma edge + * detection should *NOT* be sRGB. + * + * 6. Before including SMAA.h you'll have to setup the render target metrics, + * the target and any optional configuration defines. Optionally you can + * use a preset. + * + * You have the following targets available: + * SMAA_HLSL_3 + * SMAA_HLSL_4 + * SMAA_HLSL_4_1 + * SMAA_GLSL_3 * + * SMAA_GLSL_4 * + * + * * (See SMAA_INCLUDE_VS and SMAA_INCLUDE_PS below). + * + * And four presets: + * SMAA_PRESET_LOW (%60 of the quality) + * SMAA_PRESET_MEDIUM (%80 of the quality) + * SMAA_PRESET_HIGH (%95 of the quality) + * SMAA_PRESET_ULTRA (%99 of the quality) + * + * For example: + * #define SMAA_RT_METRICS float4(1.0 / 1280.0, 1.0 / 720.0, 1280.0, 720.0) + * #define SMAA_HLSL_4 + * #define SMAA_PRESET_HIGH + * #include "SMAA.h" + * + * Note that SMAA_RT_METRICS doesn't need to be a macro, it can be a + * uniform variable. The code is designed to minimize the impact of not + * using a constant value, but it is still better to hardcode it. + * + * Depending on how you encoded 'areaTex' and 'searchTex', you may have to + * add (and customize) the following defines before including SMAA.h: + * #define SMAA_AREATEX_SELECT(sample) sample.rg + * #define SMAA_SEARCHTEX_SELECT(sample) sample.r + * + * If your engine is already using porting macros, you can define + * SMAA_CUSTOM_SL, and define the porting functions by yourself. + * + * 7. Then, you'll have to setup the passes as indicated in the scheme above. + * You can take a look into SMAA.fx, to see how we did it for our demo. + * Checkout the function wrappers, you may want to copy-paste them! + * + * 8. It's recommended to validate the produced |edgesTex| and |blendTex|. + * You can use a screenshot from your engine to compare the |edgesTex| + * and |blendTex| produced inside of the engine with the results obtained + * with the reference demo. + * + * 9. After you get the last pass to work, it's time to optimize. You'll have + * to initialize a stencil buffer in the first pass (discard is already in + * the code), then mask execution by using it the second pass. The last + * pass should be executed in all pixels. + * + * + * After this point you can choose to enable predicated thresholding, + * temporal supersampling and motion blur integration: + * + * a) If you want to use predicated thresholding, take a look into + * SMAA_PREDICATION; you'll need to pass an extra texture in the edge + * detection pass. + * + * b) If you want to enable temporal supersampling (SMAA T2x): + * + * 1. The first step is to render using subpixel jitters. I won't go into + * detail, but it's as simple as moving each vertex position in the + * vertex shader, you can check how we do it in our DX10 demo. + * + * 2. Then, you must setup the temporal resolve. You may want to take a look + * into SMAAResolve for resolving 2x modes. After you get it working, you'll + * probably see ghosting everywhere. But fear not, you can enable the + * CryENGINE temporal reprojection by setting the SMAA_REPROJECTION macro. + * Check out SMAA_DECODE_VELOCITY if your velocity buffer is encoded. + * + * 3. The next step is to apply SMAA to each subpixel jittered frame, just as + * done for 1x. + * + * 4. At this point you should already have something usable, but for best + * results the proper area textures must be set depending on current jitter. + * For this, the parameter 'subsampleIndices' of + * 'SMAABlendingWeightCalculationPS' must be set as follows, for our T2x + * mode: + * + * @SUBSAMPLE_INDICES + * + * | S# | Camera Jitter | subsampleIndices | + * +----+------------------+---------------------+ + * | 0 | ( 0.25, -0.25) | float4(1, 1, 1, 0) | + * | 1 | (-0.25, 0.25) | float4(2, 2, 2, 0) | + * + * These jitter positions assume a bottom-to-top y axis. S# stands for the + * sample number. + * + * More information about temporal supersampling here: + * http://iryoku.com/aacourse/downloads/13-Anti-Aliasing-Methods-in-CryENGINE-3.pdf + * + * c) If you want to enable spatial multisampling (SMAA S2x): + * + * 1. The scene must be rendered using MSAA 2x. The MSAA 2x buffer must be + * created with: + * - DX10: see below (*) + * - DX10.1: D3D10_STANDARD_MULTISAMPLE_PATTERN or + * - DX11: D3D11_STANDARD_MULTISAMPLE_PATTERN + * + * This allows to ensure that the subsample order matches the table in + * @SUBSAMPLE_INDICES. + * + * (*) In the case of DX10, we refer the reader to: + * - SMAA::detectMSAAOrder and + * - SMAA::msaaReorder + * + * These functions allow to match the standard multisample patterns by + * detecting the subsample order for a specific GPU, and reordering + * them appropriately. + * + * 2. A shader must be run to output each subsample into a separate buffer + * (DX10 is required). You can use SMAASeparate for this purpose, or just do + * it in an existing pass (for example, in the tone mapping pass, which has + * the advantage of feeding tone mapped subsamples to SMAA, which will yield + * better results). + * + * 3. The full SMAA 1x pipeline must be run for each separated buffer, storing + * the results in the final buffer. The second run should alpha blend with + * the existing final buffer using a blending factor of 0.5. + * 'subsampleIndices' must be adjusted as in the SMAA T2x case (see point + * b). + * + * d) If you want to enable temporal supersampling on top of SMAA S2x + * (which actually is SMAA 4x): + * + * 1. SMAA 4x consists on temporally jittering SMAA S2x, so the first step is + * to calculate SMAA S2x for current frame. In this case, 'subsampleIndices' + * must be set as follows: + * + * | F# | S# | Camera Jitter | Net Jitter | subsampleIndices | + * +----+----+--------------------+-------------------+----------------------+ + * | 0 | 0 | ( 0.125, 0.125) | ( 0.375, -0.125) | float4(5, 3, 1, 3) | + * | 0 | 1 | ( 0.125, 0.125) | (-0.125, 0.375) | float4(4, 6, 2, 3) | + * +----+----+--------------------+-------------------+----------------------+ + * | 1 | 2 | (-0.125, -0.125) | ( 0.125, -0.375) | float4(3, 5, 1, 4) | + * | 1 | 3 | (-0.125, -0.125) | (-0.375, 0.125) | float4(6, 4, 2, 4) | + * + * These jitter positions assume a bottom-to-top y axis. F# stands for the + * frame number. S# stands for the sample number. + * + * 2. After calculating SMAA S2x for current frame (with the new subsample + * indices), previous frame must be reprojected as in SMAA T2x mode (see + * point b). + * + * e) If motion blur is used, you may want to do the edge detection pass + * together with motion blur. This has two advantages: + * + * 1. Pixels under heavy motion can be omitted from the edge detection process. + * For these pixels we can just store "no edge", as motion blur will take + * care of them. + * 2. The center pixel tap is reused. + * + * Note that in this case depth testing should be used instead of stenciling, + * as we have to write all the pixels in the motion blur pass. + * + * That's it! + */ + +//----------------------------------------------------------------------------- +// SMAA Presets + +/** + * Note that if you use one of these presets, the following configuration + * macros will be ignored if set in the "Configurable Defines" section. + */ + +#if defined(SMAA_PRESET_LOW) +#define SMAA_THRESHOLD 0.15 +#define SMAA_MAX_SEARCH_STEPS 4 +#define SMAA_DISABLE_DIAG_DETECTION +#define SMAA_DISABLE_CORNER_DETECTION +#elif defined(SMAA_PRESET_MEDIUM) +#define SMAA_THRESHOLD 0.1 +#define SMAA_MAX_SEARCH_STEPS 8 +#define SMAA_DISABLE_DIAG_DETECTION +#define SMAA_DISABLE_CORNER_DETECTION +#elif defined(SMAA_PRESET_HIGH) +#define SMAA_THRESHOLD 0.1 +#define SMAA_MAX_SEARCH_STEPS 16 +#define SMAA_MAX_SEARCH_STEPS_DIAG 8 +#define SMAA_CORNER_ROUNDING 25 +#elif defined(SMAA_PRESET_ULTRA) +#define SMAA_THRESHOLD 0.05 +#define SMAA_MAX_SEARCH_STEPS 32 +#define SMAA_MAX_SEARCH_STEPS_DIAG 16 +#define SMAA_CORNER_ROUNDING 25 +#endif + +//----------------------------------------------------------------------------- +// Configurable Defines + +/** + * SMAA_THRESHOLD specifies the threshold or sensitivity to edges. + * Lowering this value you will be able to detect more edges at the expense of + * performance. + * + * Range: [0, 0.5] + * 0.1 is a reasonable value, and allows to catch most visible edges. + * 0.05 is a rather overkill value, that allows to catch 'em all. + * + * If temporal supersampling is used, 0.2 could be a reasonable value, as low + * contrast edges are properly filtered by just 2x. + */ +#ifndef SMAA_THRESHOLD +#define SMAA_THRESHOLD 0.1 +#endif + +/** + * SMAA_DEPTH_THRESHOLD specifies the threshold for depth edge detection. + * + * Range: depends on the depth range of the scene. + */ +#ifndef SMAA_DEPTH_THRESHOLD +#define SMAA_DEPTH_THRESHOLD (0.1 * SMAA_THRESHOLD) +#endif + +/** + * SMAA_MAX_SEARCH_STEPS specifies the maximum steps performed in the + * horizontal/vertical pattern searches, at each side of the pixel. + * + * In number of pixels, it's actually the double. So the maximum line length + * perfectly handled by, for example 16, is 64 (by perfectly, we meant that + * longer lines won't look as good, but still antialiased). + * + * Range: [0, 112] + */ +#ifndef SMAA_MAX_SEARCH_STEPS +#define SMAA_MAX_SEARCH_STEPS 16 +#endif + +/** + * SMAA_MAX_SEARCH_STEPS_DIAG specifies the maximum steps performed in the + * diagonal pattern searches, at each side of the pixel. In this case we jump + * one pixel at time, instead of two. + * + * Range: [0, 20] + * + * On high-end machines it is cheap (between a 0.8x and 0.9x slower for 16 + * steps), but it can have a significant impact on older machines. + * + * Define SMAA_DISABLE_DIAG_DETECTION to disable diagonal processing. + */ +#ifndef SMAA_MAX_SEARCH_STEPS_DIAG +#define SMAA_MAX_SEARCH_STEPS_DIAG 8 +#endif + +/** + * SMAA_CORNER_ROUNDING specifies how much sharp corners will be rounded. + * + * Range: [0, 100] + * + * Define SMAA_DISABLE_CORNER_DETECTION to disable corner processing. + */ +#ifndef SMAA_CORNER_ROUNDING +#define SMAA_CORNER_ROUNDING 25 +#endif + +/** + * If there is an neighbor edge that has SMAA_LOCAL_CONTRAST_FACTOR times + * bigger contrast than current edge, current edge will be discarded. + * + * This allows to eliminate spurious crossing edges, and is based on the fact + * that, if there is too much contrast in a direction, that will hide + * perceptually contrast in the other neighbors. + */ +#ifndef SMAA_LOCAL_CONTRAST_ADAPTATION_FACTOR +#define SMAA_LOCAL_CONTRAST_ADAPTATION_FACTOR 2.0 +#endif + +/** + * Predicated thresholding allows to better preserve texture details and to + * improve performance, by decreasing the number of detected edges using an + * additional buffer like the light accumulation buffer, object ids or even the + * depth buffer (the depth buffer usage may be limited to indoor or short range + * scenes). + * + * It locally decreases the luma or color threshold if an edge is found in an + * additional buffer (so the global threshold can be higher). + * + * This method was developed by Playstation EDGE MLAA team, and used in + * Killzone 3, by using the light accumulation buffer. More information here: + * http://iryoku.com/aacourse/downloads/06-MLAA-on-PS3.pptx + */ +#ifndef SMAA_PREDICATION +#define SMAA_PREDICATION 0 +#endif + +/** + * Threshold to be used in the additional predication buffer. + * + * Range: depends on the input, so you'll have to find the magic number that + * works for you. + */ +#ifndef SMAA_PREDICATION_THRESHOLD +#define SMAA_PREDICATION_THRESHOLD 0.01 +#endif + +/** + * How much to scale the global threshold used for luma or color edge + * detection when using predication. + * + * Range: [1, 5] + */ +#ifndef SMAA_PREDICATION_SCALE +#define SMAA_PREDICATION_SCALE 2.0 +#endif + +/** + * How much to locally decrease the threshold. + * + * Range: [0, 1] + */ +#ifndef SMAA_PREDICATION_STRENGTH +#define SMAA_PREDICATION_STRENGTH 0.4 +#endif + +/** + * Temporal reprojection allows to remove ghosting artifacts when using + * temporal supersampling. We use the CryEngine 3 method which also introduces + * velocity weighting. This feature is of extreme importance for totally + * removing ghosting. More information here: + * http://iryoku.com/aacourse/downloads/13-Anti-Aliasing-Methods-in-CryENGINE-3.pdf + * + * Note that you'll need to setup a velocity buffer for enabling reprojection. + * For static geometry, saving the previous depth buffer is a viable + * alternative. + */ +#ifndef SMAA_REPROJECTION +#define SMAA_REPROJECTION 0 +#endif + +/** + * Temporal reprojection allows to remove ghosting artifacts when using + * temporal supersampling. However, the default reprojection requires a velocity buffer + * in order to function properly. + * + * A velocity buffer might not always be available (hi Unity 5!). To handle such cases + * we provide a UV-based approximation for calculating motion vectors on the fly. + */ +#ifndef SMAA_UV_BASED_REPROJECTION +#define SMAA_UV_BASED_REPROJECTION 0 +#endif + +/** + * SMAA_REPROJECTION_WEIGHT_SCALE controls the velocity weighting. It allows to + * remove ghosting trails behind the moving object, which are not removed by + * just using reprojection. Using low values will exhibit ghosting, while using + * high values will disable temporal supersampling under motion. + * + * Behind the scenes, velocity weighting removes temporal supersampling when + * the velocity of the subsamples differs (meaning they are different objects). + * + * Range: [0, 80] + */ +#ifndef SMAA_REPROJECTION_WEIGHT_SCALE +#define SMAA_REPROJECTION_WEIGHT_SCALE 30.0 +#endif + +/** + * On some compilers, discard cannot be used in vertex shaders. Thus, they need + * to be compiled separately. + */ +#ifndef SMAA_INCLUDE_VS +#define SMAA_INCLUDE_VS 1 +#endif +#ifndef SMAA_INCLUDE_PS +#define SMAA_INCLUDE_PS 1 +#endif + +//----------------------------------------------------------------------------- +// Texture Access Defines + +#ifndef SMAA_AREATEX_SELECT +#if defined(SMAA_HLSL_3) +#define SMAA_AREATEX_SELECT(sample) sample.ra +#else +#define SMAA_AREATEX_SELECT(sample) sample.rg +#endif +#endif + +#ifndef SMAA_SEARCHTEX_SELECT +#define SMAA_SEARCHTEX_SELECT(sample) sample.r +#endif + +#ifndef SMAA_DECODE_VELOCITY +#define SMAA_DECODE_VELOCITY(sample) sample.rg +#endif + +//----------------------------------------------------------------------------- +// Non-Configurable Defines + +#define SMAA_AREATEX_MAX_DISTANCE 16 +#define SMAA_AREATEX_MAX_DISTANCE_DIAG 20 +#define SMAA_AREATEX_PIXEL_SIZE (1.0 / float2(160.0, 560.0)) +#define SMAA_AREATEX_SUBTEX_SIZE (1.0 / 7.0) +#define SMAA_SEARCHTEX_SIZE float2(66.0, 33.0) +#define SMAA_SEARCHTEX_PACKED_SIZE float2(64.0, 16.0) +#define SMAA_CORNER_ROUNDING_NORM (float(SMAA_CORNER_ROUNDING) / 100.0) + +//----------------------------------------------------------------------------- +// Porting Functions + +#if defined(SMAA_HLSL_3) +#define SMAATexture2D(tex) sampler2D tex +#define SMAATexturePass2D(tex) tex +#define SMAASampleLevelZero(tex, coord) tex2Dlod(tex, float4(coord, 0.0, 0.0)) +#define SMAASampleLevelZeroPoint(tex, coord) tex2Dlod(tex, float4(coord, 0.0, 0.0)) +#define SMAASampleLevelZeroOffset(tex, coord, offset) tex2Dlod(tex, float4(coord + offset * SMAA_RT_METRICS.xy, 0.0, 0.0)) +#define SMAASample(tex, coord) tex2D(tex, coord) +#define SMAASamplePoint(tex, coord) tex2D(tex, coord) +#define SMAASampleOffset(tex, coord, offset) tex2D(tex, coord + offset * SMAA_RT_METRICS.xy) +#define SMAA_FLATTEN [flatten] +#define SMAA_BRANCH [branch] +#endif +#if defined(SMAA_HLSL_4) || defined(SMAA_HLSL_4_1) +SamplerState LinearSampler { Filter = MIN_MAG_LINEAR_MIP_POINT; AddressU = Clamp; AddressV = Clamp; }; +SamplerState PointSampler { Filter = MIN_MAG_MIP_POINT; AddressU = Clamp; AddressV = Clamp; }; +#define SMAATexture2D(tex) Texture2D tex +#define SMAATexturePass2D(tex) tex +#define SMAASampleLevelZero(tex, coord) tex.SampleLevel(LinearSampler, coord, 0) +#define SMAASampleLevelZeroPoint(tex, coord) tex.SampleLevel(PointSampler, coord, 0) +#define SMAASampleLevelZeroOffset(tex, coord, offset) tex.SampleLevel(LinearSampler, coord, 0, offset) +#define SMAASample(tex, coord) tex.Sample(LinearSampler, coord) +#define SMAASamplePoint(tex, coord) tex.Sample(PointSampler, coord) +#define SMAASampleOffset(tex, coord, offset) tex.Sample(LinearSampler, coord, offset) +#define SMAA_FLATTEN [flatten] +#define SMAA_BRANCH [branch] +#define SMAATexture2DMS2(tex) Texture2DMS tex +#define SMAALoad(tex, pos, sample) tex.Load(pos, sample) +#if defined(SMAA_HLSL_4_1) +#define SMAAGather(tex, coord) tex.Gather(LinearSampler, coord, 0) +#endif +#endif +#if defined(SMAA_GLSL_3) || defined(SMAA_GLSL_4) +#define SMAATexture2D(tex) sampler2D tex +#define SMAATexturePass2D(tex) tex +#define SMAASampleLevelZero(tex, coord) textureLod(tex, coord, 0.0) +#define SMAASampleLevelZeroPoint(tex, coord) textureLod(tex, coord, 0.0) +#define SMAASampleLevelZeroOffset(tex, coord, offset) textureLodOffset(tex, coord, 0.0, offset) +#define SMAASample(tex, coord) texture(tex, coord) +#define SMAASamplePoint(tex, coord) texture(tex, coord) +#define SMAASampleOffset(tex, coord, offset) texture(tex, coord, offset) +#define SMAA_FLATTEN +#define SMAA_BRANCH +#define lerp(a, b, t) mix(a, b, t) +#define saturate(a) clamp(a, 0.0, 1.0) +#if defined(SMAA_GLSL_4) +#define mad(a, b, c) fma(a, b, c) +#define SMAAGather(tex, coord) textureGather(tex, coord) +#else +#define mad(a, b, c) (a * b + c) +#endif +#define float2 vec2 +#define float3 vec3 +#define float4 vec4 +#define int2 ivec2 +#define int3 ivec3 +#define int4 ivec4 +#define bool2 bvec2 +#define bool3 bvec3 +#define bool4 bvec4 +#endif + +#if !defined(SMAA_HLSL_3) && !defined(SMAA_HLSL_4) && !defined(SMAA_HLSL_4_1) && !defined(SMAA_GLSL_3) && !defined(SMAA_GLSL_4) && !defined(SMAA_CUSTOM_SL) +#error you must define the shading language: SMAA_HLSL_*, SMAA_GLSL_* or SMAA_CUSTOM_SL +#endif + +//----------------------------------------------------------------------------- +// Misc functions + +/** + * Gathers current pixel, and the top-left neighbors. + */ +float3 SMAAGatherNeighbours(float2 texcoord, + float4 offset[3], + SMAATexture2D(tex)) { + #ifdef SMAAGather + return SMAAGather(tex, texcoord + SMAA_RT_METRICS.xy * float2(-0.5, -0.5)).grb; + #else + float P = SMAASamplePoint(tex, texcoord).r; + float Pleft = SMAASamplePoint(tex, offset[0].xy).r; + float Ptop = SMAASamplePoint(tex, offset[0].zw).r; + return float3(P, Pleft, Ptop); + #endif +} + +/** + * Adjusts the threshold by means of predication. + */ +float2 SMAACalculatePredicatedThreshold(float2 texcoord, + float4 offset[3], + SMAATexture2D(predicationTex)) { + float3 neighbours = SMAAGatherNeighbours(texcoord, offset, SMAATexturePass2D(predicationTex)); + float2 delta = abs(neighbours.xx - neighbours.yz); + float2 edges = step(SMAA_PREDICATION_THRESHOLD, delta); + return SMAA_PREDICATION_SCALE * SMAA_THRESHOLD * (1.0 - SMAA_PREDICATION_STRENGTH * edges); +} + +/** + * Conditional move: + */ +void SMAAMovc(bool2 cond, inout float2 variable, float2 value) { + SMAA_FLATTEN if (cond.x) variable.x = value.x; + SMAA_FLATTEN if (cond.y) variable.y = value.y; +} + +void SMAAMovc(bool4 cond, inout float4 variable, float4 value) { + SMAAMovc(cond.xy, variable.xy, value.xy); + SMAAMovc(cond.zw, variable.zw, value.zw); +} + + +#if SMAA_INCLUDE_VS +//----------------------------------------------------------------------------- +// Vertex Shaders + +/** + * Edge Detection Vertex Shader + */ +void SMAAEdgeDetectionVS(float2 texcoord, + out float4 offset[3]) { + offset[0] = mad(SMAA_RT_METRICS.xyxy, float4(-1.0, 0.0, 0.0, -1.0), texcoord.xyxy); + offset[1] = mad(SMAA_RT_METRICS.xyxy, float4( 1.0, 0.0, 0.0, 1.0), texcoord.xyxy); + offset[2] = mad(SMAA_RT_METRICS.xyxy, float4(-2.0, 0.0, 0.0, -2.0), texcoord.xyxy); +} + +/** + * Blend Weight Calculation Vertex Shader + */ +void SMAABlendingWeightCalculationVS(float2 texcoord, + out float2 pixcoord, + out float4 offset[3]) { + pixcoord = texcoord * SMAA_RT_METRICS.zw; + + // We will use these offsets for the searches later on (see @PSEUDO_GATHER4): + offset[0] = mad(SMAA_RT_METRICS.xyxy, float4(-0.25, -0.125, 1.25, -0.125), texcoord.xyxy); + offset[1] = mad(SMAA_RT_METRICS.xyxy, float4(-0.125, -0.25, -0.125, 1.25), texcoord.xyxy); + + // And these for the searches, they indicate the ends of the loops: + offset[2] = mad(SMAA_RT_METRICS.xxyy, + float4(-2.0, 2.0, -2.0, 2.0) * float(SMAA_MAX_SEARCH_STEPS), + float4(offset[0].xz, offset[1].yw)); +} + +/** + * Neighborhood Blending Vertex Shader + */ +void SMAANeighborhoodBlendingVS(float2 texcoord, + out float4 offset) { + offset = mad(SMAA_RT_METRICS.xyxy, float4( 1.0, 0.0, 0.0, 1.0), texcoord.xyxy); +} +#endif // SMAA_INCLUDE_VS + +#if SMAA_INCLUDE_PS +//----------------------------------------------------------------------------- +// Edge Detection Pixel Shaders (First Pass) + +/** + * Luma Edge Detection + * + * IMPORTANT NOTICE: luma edge detection requires gamma-corrected colors, and + * thus 'colorTex' should be a non-sRGB texture. + */ +float2 SMAALumaEdgeDetectionPS(float2 texcoord, + float4 offset[3], + SMAATexture2D(colorTex) + #if SMAA_PREDICATION + , SMAATexture2D(predicationTex) + #endif + ) { + // Calculate the threshold: + #if SMAA_PREDICATION + float2 threshold = SMAACalculatePredicatedThreshold(texcoord, offset, SMAATexturePass2D(predicationTex)); + #else + float2 threshold = float2(SMAA_THRESHOLD, SMAA_THRESHOLD); + #endif + + // Calculate lumas: + float3 weights = float3(0.2126, 0.7152, 0.0722); + float L = dot(SMAASamplePoint(colorTex, texcoord).rgb, weights); + + float Lleft = dot(SMAASamplePoint(colorTex, offset[0].xy).rgb, weights); + float Ltop = dot(SMAASamplePoint(colorTex, offset[0].zw).rgb, weights); + + // We do the usual threshold: + float4 delta; + delta.xy = abs(L - float2(Lleft, Ltop)); + float2 edges = step(threshold, delta.xy); + + // Then discard if there is no edge: + if (dot(edges, float2(1.0, 1.0)) == 0.0) + discard; + + // Calculate right and bottom deltas: + float Lright = dot(SMAASamplePoint(colorTex, offset[1].xy).rgb, weights); + float Lbottom = dot(SMAASamplePoint(colorTex, offset[1].zw).rgb, weights); + delta.zw = abs(L - float2(Lright, Lbottom)); + + // Calculate the maximum delta in the direct neighborhood: + float2 maxDelta = max(delta.xy, delta.zw); + + // Calculate left-left and top-top deltas: + float Lleftleft = dot(SMAASamplePoint(colorTex, offset[2].xy).rgb, weights); + float Ltoptop = dot(SMAASamplePoint(colorTex, offset[2].zw).rgb, weights); + delta.zw = abs(float2(Lleft, Ltop) - float2(Lleftleft, Ltoptop)); + + // Calculate the final maximum delta: + maxDelta = max(maxDelta.xy, delta.zw); + float finalDelta = max(maxDelta.x, maxDelta.y); + + // Local contrast adaptation: +#if !defined(SHADER_API_OPENGL) + edges.xy *= step(finalDelta, SMAA_LOCAL_CONTRAST_ADAPTATION_FACTOR * delta.xy); +#endif + + return edges; +} + +/** + * Color Edge Detection + * + * IMPORTANT NOTICE: color edge detection requires gamma-corrected colors, and + * thus 'colorTex' should be a non-sRGB texture. + */ +float2 SMAAColorEdgeDetectionPS(float2 texcoord, + float4 offset[3], + SMAATexture2D(colorTex) + #if SMAA_PREDICATION + , SMAATexture2D(predicationTex) + #endif + ) { + // Calculate the threshold: + #if SMAA_PREDICATION + float2 threshold = SMAACalculatePredicatedThreshold(texcoord, offset, predicationTex); + #else + float2 threshold = float2(SMAA_THRESHOLD, SMAA_THRESHOLD); + #endif + + // Calculate color deltas: + float4 delta; + float3 C = SMAASamplePoint(colorTex, texcoord).rgb; + + float3 Cleft = SMAASamplePoint(colorTex, offset[0].xy).rgb; + float3 t = abs(C - Cleft); + delta.x = max(max(t.r, t.g), t.b); + + float3 Ctop = SMAASamplePoint(colorTex, offset[0].zw).rgb; + t = abs(C - Ctop); + delta.y = max(max(t.r, t.g), t.b); + + // We do the usual threshold: + float2 edges = step(threshold, delta.xy); + + // Then discard if there is no edge: + if (dot(edges, float2(1.0, 1.0)) == 0.0) + discard; + + // Calculate right and bottom deltas: + float3 Cright = SMAASamplePoint(colorTex, offset[1].xy).rgb; + t = abs(C - Cright); + delta.z = max(max(t.r, t.g), t.b); + + float3 Cbottom = SMAASamplePoint(colorTex, offset[1].zw).rgb; + t = abs(C - Cbottom); + delta.w = max(max(t.r, t.g), t.b); + + // Calculate the maximum delta in the direct neighborhood: + float2 maxDelta = max(delta.xy, delta.zw); + + // Calculate left-left and top-top deltas: + float3 Cleftleft = SMAASamplePoint(colorTex, offset[2].xy).rgb; + t = abs(C - Cleftleft); + delta.z = max(max(t.r, t.g), t.b); + + float3 Ctoptop = SMAASamplePoint(colorTex, offset[2].zw).rgb; + t = abs(C - Ctoptop); + delta.w = max(max(t.r, t.g), t.b); + + // Calculate the final maximum delta: + maxDelta = max(maxDelta.xy, delta.zw); + float finalDelta = max(maxDelta.x, maxDelta.y); + + // Local contrast adaptation: +#if !defined(SHADER_API_OPENGL) + edges.xy *= step(finalDelta, SMAA_LOCAL_CONTRAST_ADAPTATION_FACTOR * delta.xy); +#endif + + return edges; +} + +/** + * Depth Edge Detection + */ +float2 SMAADepthEdgeDetectionPS(float2 texcoord, + float4 offset[3], + SMAATexture2D(depthTex)) { + float3 neighbours = SMAAGatherNeighbours(texcoord, offset, SMAATexturePass2D(depthTex)); + float2 delta = abs(neighbours.xx - float2(neighbours.y, neighbours.z)); + float2 edges = step(SMAA_DEPTH_THRESHOLD, delta); + + if (dot(edges, float2(1.0, 1.0)) == 0.0) + discard; + + return edges; +} + +//----------------------------------------------------------------------------- +// Diagonal Search Functions + +#if !defined(SMAA_DISABLE_DIAG_DETECTION) + +/** + * Allows to decode two binary values from a bilinear-filtered access. + */ +float2 SMAADecodeDiagBilinearAccess(float2 e) { + // Bilinear access for fetching 'e' have a 0.25 offset, and we are + // interested in the R and G edges: + // + // +---G---+-------+ + // | x o R x | + // +-------+-------+ + // + // Then, if one of these edge is enabled: + // Red: (0.75 * X + 0.25 * 1) => 0.25 or 1.0 + // Green: (0.75 * 1 + 0.25 * X) => 0.75 or 1.0 + // + // This function will unpack the values (mad + mul + round): + // wolframalpha.com: round(x * abs(5 * x - 5 * 0.75)) plot 0 to 1 + e.r = e.r * abs(5.0 * e.r - 5.0 * 0.75); + return round(e); +} + +float4 SMAADecodeDiagBilinearAccess(float4 e) { + e.rb = e.rb * abs(5.0 * e.rb - 5.0 * 0.75); + return round(e); +} + +/** + * These functions allows to perform diagonal pattern searches. + */ +float2 SMAASearchDiag1(SMAATexture2D(edgesTex), float2 texcoord, float2 dir, out float2 e) { + float4 coord = float4(texcoord, -1.0, 1.0); + float3 t = float3(SMAA_RT_METRICS.xy, 1.0); + while (coord.z < float(SMAA_MAX_SEARCH_STEPS_DIAG - 1) && + coord.w > 0.9) { + coord.xyz = mad(t, float3(dir, 1.0), coord.xyz); + e = SMAASampleLevelZero(edgesTex, coord.xy).rg; + coord.w = dot(e, float2(0.5, 0.5)); + } + return coord.zw; +} + +float2 SMAASearchDiag2(SMAATexture2D(edgesTex), float2 texcoord, float2 dir, out float2 e) { + float4 coord = float4(texcoord, -1.0, 1.0); + coord.x += 0.25 * SMAA_RT_METRICS.x; // See @SearchDiag2Optimization + float3 t = float3(SMAA_RT_METRICS.xy, 1.0); + while (coord.z < float(SMAA_MAX_SEARCH_STEPS_DIAG - 1) && + coord.w > 0.9) { + coord.xyz = mad(t, float3(dir, 1.0), coord.xyz); + + // @SearchDiag2Optimization + // Fetch both edges at once using bilinear filtering: + e = SMAASampleLevelZero(edgesTex, coord.xy).rg; + e = SMAADecodeDiagBilinearAccess(e); + + // Non-optimized version: + // e.g = SMAASampleLevelZero(edgesTex, coord.xy).g; + // e.r = SMAASampleLevelZeroOffset(edgesTex, coord.xy, int2(1, 0)).r; + + coord.w = dot(e, float2(0.5, 0.5)); + } + return coord.zw; +} + +/** + * Similar to SMAAArea, this calculates the area corresponding to a certain + * diagonal distance and crossing edges 'e'. + */ +float2 SMAAAreaDiag(SMAATexture2D(areaTex), float2 dist, float2 e, float offset) { + float2 texcoord = mad(float2(SMAA_AREATEX_MAX_DISTANCE_DIAG, SMAA_AREATEX_MAX_DISTANCE_DIAG), e, dist); + + // We do a scale and bias for mapping to texel space: + texcoord = mad(SMAA_AREATEX_PIXEL_SIZE, texcoord, 0.5 * SMAA_AREATEX_PIXEL_SIZE); + + // Diagonal areas are on the second half of the texture: + texcoord.x += 0.5; + + // Move to proper place, according to the subpixel offset: + texcoord.y += SMAA_AREATEX_SUBTEX_SIZE * offset; + + // Do it! + return SMAA_AREATEX_SELECT(SMAASampleLevelZero(areaTex, texcoord)); +} + +/** + * This searches for diagonal patterns and returns the corresponding weights. + */ +float2 SMAACalculateDiagWeights(SMAATexture2D(edgesTex), SMAATexture2D(areaTex), float2 texcoord, float2 e, float4 subsampleIndices) { + float2 weights = float2(0.0, 0.0); + + // Search for the line ends: + float4 d; + float2 end; + if (e.r > 0.0) { + d.xz = SMAASearchDiag1(SMAATexturePass2D(edgesTex), texcoord, float2(-1.0, 1.0), end); + d.x += float(end.y > 0.9); + } else + d.xz = float2(0.0, 0.0); + d.yw = SMAASearchDiag1(SMAATexturePass2D(edgesTex), texcoord, float2(1.0, -1.0), end); + + SMAA_BRANCH + if (d.x + d.y > 2.0) { // d.x + d.y + 1 > 3 + // Fetch the crossing edges: + float4 coords = mad(float4(-d.x + 0.25, d.x, d.y, -d.y - 0.25), SMAA_RT_METRICS.xyxy, texcoord.xyxy); + float4 c; + c.xy = SMAASampleLevelZeroOffset(edgesTex, coords.xy, int2(-1, 0)).rg; + c.zw = SMAASampleLevelZeroOffset(edgesTex, coords.zw, int2( 1, 0)).rg; + c.yxwz = SMAADecodeDiagBilinearAccess(c.xyzw); + + // Non-optimized version: + // float4 coords = mad(float4(-d.x, d.x, d.y, -d.y), SMAA_RT_METRICS.xyxy, texcoord.xyxy); + // float4 c; + // c.x = SMAASampleLevelZeroOffset(edgesTex, coords.xy, int2(-1, 0)).g; + // c.y = SMAASampleLevelZeroOffset(edgesTex, coords.xy, int2( 0, 0)).r; + // c.z = SMAASampleLevelZeroOffset(edgesTex, coords.zw, int2( 1, 0)).g; + // c.w = SMAASampleLevelZeroOffset(edgesTex, coords.zw, int2( 1, -1)).r; + + // Merge crossing edges at each side into a single value: + float2 cc = mad(float2(2.0, 2.0), c.xz, c.yw); + + // Remove the crossing edge if we didn't found the end of the line: + SMAAMovc(bool2(step(float2(0.9, 0.9), d.zw)), cc, float2(0.0, 0.0)); + + // Fetch the areas for this line: + weights += SMAAAreaDiag(SMAATexturePass2D(areaTex), d.xy, cc, subsampleIndices.z); + } + + // Search for the line ends: + d.xz = SMAASearchDiag2(SMAATexturePass2D(edgesTex), texcoord, float2(-1.0, -1.0), end); + if (SMAASampleLevelZeroOffset(edgesTex, texcoord, int2(1, 0)).r > 0.0) { + d.yw = SMAASearchDiag2(SMAATexturePass2D(edgesTex), texcoord, float2(1.0, 1.0), end); + d.y += float(end.y > 0.9); + } else + d.yw = float2(0.0, 0.0); + + SMAA_BRANCH + if (d.x + d.y > 2.0) { // d.x + d.y + 1 > 3 + // Fetch the crossing edges: + float4 coords = mad(float4(-d.x, -d.x, d.y, d.y), SMAA_RT_METRICS.xyxy, texcoord.xyxy); + float4 c; + c.x = SMAASampleLevelZeroOffset(edgesTex, coords.xy, int2(-1, 0)).g; + c.y = SMAASampleLevelZeroOffset(edgesTex, coords.xy, int2( 0, -1)).r; + c.zw = SMAASampleLevelZeroOffset(edgesTex, coords.zw, int2( 1, 0)).gr; + float2 cc = mad(float2(2.0, 2.0), c.xz, c.yw); + + // Remove the crossing edge if we didn't found the end of the line: + SMAAMovc(bool2(step(float2(0.9, 0.9), d.zw)), cc, float2(0.0, 0.0)); + + // Fetch the areas for this line: + weights += SMAAAreaDiag(SMAATexturePass2D(areaTex), d.xy, cc, subsampleIndices.w).gr; + } + + return weights; +} +#endif + +//----------------------------------------------------------------------------- +// Horizontal/Vertical Search Functions + +/** + * This allows to determine how much length should we add in the last step + * of the searches. It takes the bilinearly interpolated edge (see + * @PSEUDO_GATHER4), and adds 0, 1 or 2, depending on which edges and + * crossing edges are active. + */ +float SMAASearchLength(SMAATexture2D(searchTex), float2 e, float offset) { + // The texture is flipped vertically, with left and right cases taking half + // of the space horizontally: + float2 scale = SMAA_SEARCHTEX_SIZE * float2(0.5, -1.0); + float2 bias = SMAA_SEARCHTEX_SIZE * float2(offset, 1.0); + + // Scale and bias to access texel centers: + scale += float2(-1.0, 1.0); + bias += float2( 0.5, -0.5); + + // Convert from pixel coordinates to texcoords: + // (We use SMAA_SEARCHTEX_PACKED_SIZE because the texture is cropped) + scale *= 1.0 / SMAA_SEARCHTEX_PACKED_SIZE; + bias *= 1.0 / SMAA_SEARCHTEX_PACKED_SIZE; + + // Lookup the search texture: + return SMAA_SEARCHTEX_SELECT(SMAASampleLevelZero(searchTex, mad(scale, e, bias))); +} + +/** + * Horizontal/vertical search functions for the 2nd pass. + */ +float SMAASearchXLeft(SMAATexture2D(edgesTex), SMAATexture2D(searchTex), float2 texcoord, float end) { + /** + * @PSEUDO_GATHER4 + * This texcoord has been offset by (-0.25, -0.125) in the vertex shader to + * sample between edge, thus fetching four edges in a row. + * Sampling with different offsets in each direction allows to disambiguate + * which edges are active from the four fetched ones. + */ + float2 e = float2(0.0, 1.0); + while (texcoord.x > end && + e.g > 0.8281 && // Is there some edge not activated? + e.r == 0.0) { // Or is there a crossing edge that breaks the line? + e = SMAASampleLevelZero(edgesTex, texcoord).rg; + texcoord = mad(-float2(2.0, 0.0), SMAA_RT_METRICS.xy, texcoord); + } + + float offset = mad(-(255.0 / 127.0), SMAASearchLength(SMAATexturePass2D(searchTex), e, 0.0), 3.25); + return mad(SMAA_RT_METRICS.x, offset, texcoord.x); + + // Non-optimized version: + // We correct the previous (-0.25, -0.125) offset we applied: + // texcoord.x += 0.25 * SMAA_RT_METRICS.x; + + // The searches are bias by 1, so adjust the coords accordingly: + // texcoord.x += SMAA_RT_METRICS.x; + + // Disambiguate the length added by the last step: + // texcoord.x += 2.0 * SMAA_RT_METRICS.x; // Undo last step + // texcoord.x -= SMAA_RT_METRICS.x * (255.0 / 127.0) * SMAASearchLength(SMAATexturePass2D(searchTex), e, 0.0); + // return mad(SMAA_RT_METRICS.x, offset, texcoord.x); +} + +float SMAASearchXRight(SMAATexture2D(edgesTex), SMAATexture2D(searchTex), float2 texcoord, float end) { + float2 e = float2(0.0, 1.0); + while (texcoord.x < end && + e.g > 0.8281 && // Is there some edge not activated? + e.r == 0.0) { // Or is there a crossing edge that breaks the line? + e = SMAASampleLevelZero(edgesTex, texcoord).rg; + texcoord = mad(float2(2.0, 0.0), SMAA_RT_METRICS.xy, texcoord); + } + float offset = mad(-(255.0 / 127.0), SMAASearchLength(SMAATexturePass2D(searchTex), e, 0.5), 3.25); + return mad(-SMAA_RT_METRICS.x, offset, texcoord.x); +} + +float SMAASearchYUp(SMAATexture2D(edgesTex), SMAATexture2D(searchTex), float2 texcoord, float end) { + float2 e = float2(1.0, 0.0); + while (texcoord.y > end && + e.r > 0.8281 && // Is there some edge not activated? + e.g == 0.0) { // Or is there a crossing edge that breaks the line? + e = SMAASampleLevelZero(edgesTex, texcoord).rg; + texcoord = mad(-float2(0.0, 2.0), SMAA_RT_METRICS.xy, texcoord); + } + float offset = mad(-(255.0 / 127.0), SMAASearchLength(SMAATexturePass2D(searchTex), e.gr, 0.0), 3.25); + return mad(SMAA_RT_METRICS.y, offset, texcoord.y); +} + +float SMAASearchYDown(SMAATexture2D(edgesTex), SMAATexture2D(searchTex), float2 texcoord, float end) { + float2 e = float2(1.0, 0.0); + while (texcoord.y < end && + e.r > 0.8281 && // Is there some edge not activated? + e.g == 0.0) { // Or is there a crossing edge that breaks the line? + e = SMAASampleLevelZero(edgesTex, texcoord).rg; + texcoord = mad(float2(0.0, 2.0), SMAA_RT_METRICS.xy, texcoord); + } + float offset = mad(-(255.0 / 127.0), SMAASearchLength(SMAATexturePass2D(searchTex), e.gr, 0.5), 3.25); + return mad(-SMAA_RT_METRICS.y, offset, texcoord.y); +} + +/** + * Ok, we have the distance and both crossing edges. So, what are the areas + * at each side of current edge? + */ +float2 SMAAArea(SMAATexture2D(areaTex), float2 dist, float e1, float e2, float offset) { + // Rounding prevents precision errors of bilinear filtering: + float2 texcoord = mad(float2(SMAA_AREATEX_MAX_DISTANCE, SMAA_AREATEX_MAX_DISTANCE), round(4.0 * float2(e1, e2)), dist); + + // We do a scale and bias for mapping to texel space: + texcoord = mad(SMAA_AREATEX_PIXEL_SIZE, texcoord, 0.5 * SMAA_AREATEX_PIXEL_SIZE); + + // Move to proper place, according to the subpixel offset: + texcoord.y = mad(SMAA_AREATEX_SUBTEX_SIZE, offset, texcoord.y); + + // Do it! + return SMAA_AREATEX_SELECT(SMAASampleLevelZero(areaTex, texcoord)); +} + +//----------------------------------------------------------------------------- +// Corner Detection Functions + +void SMAADetectHorizontalCornerPattern(SMAATexture2D(edgesTex), inout float2 weights, float4 texcoord, float2 d) { + #if !defined(SMAA_DISABLE_CORNER_DETECTION) + float2 leftRight = step(d.xy, d.yx); + float2 rounding = (1.0 - SMAA_CORNER_ROUNDING_NORM) * leftRight; + + rounding /= leftRight.x + leftRight.y; // Reduce blending for pixels in the center of a line. + + float2 factor = float2(1.0, 1.0); + factor.x -= rounding.x * SMAASampleLevelZeroOffset(edgesTex, texcoord.xy, int2(0, 1)).r; + factor.x -= rounding.y * SMAASampleLevelZeroOffset(edgesTex, texcoord.zw, int2(1, 1)).r; + factor.y -= rounding.x * SMAASampleLevelZeroOffset(edgesTex, texcoord.xy, int2(0, -2)).r; + factor.y -= rounding.y * SMAASampleLevelZeroOffset(edgesTex, texcoord.zw, int2(1, -2)).r; + + weights *= saturate(factor); + #endif +} + +void SMAADetectVerticalCornerPattern(SMAATexture2D(edgesTex), inout float2 weights, float4 texcoord, float2 d) { + #if !defined(SMAA_DISABLE_CORNER_DETECTION) + float2 leftRight = step(d.xy, d.yx); + float2 rounding = (1.0 - SMAA_CORNER_ROUNDING_NORM) * leftRight; + + rounding /= leftRight.x + leftRight.y; + + float2 factor = float2(1.0, 1.0); + factor.x -= rounding.x * SMAASampleLevelZeroOffset(edgesTex, texcoord.xy, int2( 1, 0)).g; + factor.x -= rounding.y * SMAASampleLevelZeroOffset(edgesTex, texcoord.zw, int2( 1, 1)).g; + factor.y -= rounding.x * SMAASampleLevelZeroOffset(edgesTex, texcoord.xy, int2(-2, 0)).g; + factor.y -= rounding.y * SMAASampleLevelZeroOffset(edgesTex, texcoord.zw, int2(-2, 1)).g; + + weights *= saturate(factor); + #endif +} + + +//----------------------------------------------------------------------------- +// Blending Weight Calculation Pixel Shader (Second Pass) + +float4 SMAABlendingWeightCalculationPS(float2 texcoord, + float2 pixcoord, + float4 offset[3], + SMAATexture2D(edgesTex), + SMAATexture2D(areaTex), + SMAATexture2D(searchTex), + float4 subsampleIndices) { // Just pass zero for SMAA 1x, see @SUBSAMPLE_INDICES. + float4 weights = float4(0.0, 0.0, 0.0, 0.0); + + float2 e = SMAASample(edgesTex, texcoord).rg; + + SMAA_BRANCH + if (e.g > 0.0) { // Edge at north + #if !defined(SMAA_DISABLE_DIAG_DETECTION) + // Diagonals have both north and west edges, so searching for them in + // one of the boundaries is enough. + weights.rg = SMAACalculateDiagWeights(SMAATexturePass2D(edgesTex), SMAATexturePass2D(areaTex), texcoord, e, subsampleIndices); + + // We give priority to diagonals, so if we find a diagonal we skip + // horizontal/vertical processing. + SMAA_BRANCH + if (weights.r == -weights.g) { // weights.r + weights.g == 0.0 + #endif + + float2 d; + + // Find the distance to the left: + float3 coords; + coords.x = SMAASearchXLeft(SMAATexturePass2D(edgesTex), SMAATexturePass2D(searchTex), offset[0].xy, offset[2].x); + coords.y = offset[1].y; // offset[1].y = texcoord.y - 0.25 * SMAA_RT_METRICS.y (@CROSSING_OFFSET) + d.x = coords.x; + + // Now fetch the left crossing edges, two at a time using bilinear + // filtering. Sampling at -0.25 (see @CROSSING_OFFSET) enables to + // discern what value each edge has: + float e1 = SMAASampleLevelZero(edgesTex, coords.xy).r; + + // Find the distance to the right: + coords.z = SMAASearchXRight(SMAATexturePass2D(edgesTex), SMAATexturePass2D(searchTex), offset[0].zw, offset[2].y); + d.y = coords.z; + + // We want the distances to be in pixel units (doing this here allow to + // better interleave arithmetic and memory accesses): + d = abs(round(mad(SMAA_RT_METRICS.zz, d, -pixcoord.xx))); + + // SMAAArea below needs a sqrt, as the areas texture is compressed + // quadratically: + float2 sqrt_d = sqrt(d); + + // Fetch the right crossing edges: + float e2 = SMAASampleLevelZeroOffset(edgesTex, coords.zy, int2(1, 0)).r; + + // Ok, we know how this pattern looks like, now it is time for getting + // the actual area: + weights.rg = SMAAArea(SMAATexturePass2D(areaTex), sqrt_d, e1, e2, subsampleIndices.y); + + // Fix corners: + coords.y = texcoord.y; + SMAADetectHorizontalCornerPattern(SMAATexturePass2D(edgesTex), weights.rg, coords.xyzy, d); + + #if !defined(SMAA_DISABLE_DIAG_DETECTION) + } else + e.r = 0.0; // Skip vertical processing. + #endif + } + + SMAA_BRANCH + if (e.r > 0.0) { // Edge at west + float2 d; + + // Find the distance to the top: + float3 coords; + coords.y = SMAASearchYUp(SMAATexturePass2D(edgesTex), SMAATexturePass2D(searchTex), offset[1].xy, offset[2].z); + coords.x = offset[0].x; // offset[1].x = texcoord.x - 0.25 * SMAA_RT_METRICS.x; + d.x = coords.y; + + // Fetch the top crossing edges: + float e1 = SMAASampleLevelZero(edgesTex, coords.xy).g; + + // Find the distance to the bottom: + coords.z = SMAASearchYDown(SMAATexturePass2D(edgesTex), SMAATexturePass2D(searchTex), offset[1].zw, offset[2].w); + d.y = coords.z; + + // We want the distances to be in pixel units: + d = abs(round(mad(SMAA_RT_METRICS.ww, d, -pixcoord.yy))); + + // SMAAArea below needs a sqrt, as the areas texture is compressed + // quadratically: + float2 sqrt_d = sqrt(d); + + // Fetch the bottom crossing edges: + float e2 = SMAASampleLevelZeroOffset(edgesTex, coords.xz, int2(0, 1)).g; + + // Get the area for this direction: + weights.ba = SMAAArea(SMAATexturePass2D(areaTex), sqrt_d, e1, e2, subsampleIndices.x); + + // Fix corners: + coords.x = texcoord.x; + SMAADetectVerticalCornerPattern(SMAATexturePass2D(edgesTex), weights.ba, coords.xyxz, d); + } + + return weights; +} + +//----------------------------------------------------------------------------- +// UV-based reprojection functions + +#if SMAA_UV_BASED_REPROJECTION +float2 SMAAReproject(float2 texcoord) +{ + // UV to clip-position: + // -- This must be sampled at exactly mip 0 due to possible gradient divergence + // -- as this function is called within a control flow block down below. + float depth = SMAASampleLevelZero(_CameraDepthTexture, texcoord).r; + float3 clipPosition = float3(2. * texcoord - 1., depth); + + // Reproject + float4 previousClipPosition = mul(_ReprojectionMatrix, float4(clipPosition, 1.)); + previousClipPosition.xyz /= previousClipPosition.w; + + // Clip-position to UV + return (.5 * previousClipPosition.xy + .5); +} +#endif + +//----------------------------------------------------------------------------- +// Neighborhood Blending Pixel Shader (Third Pass) + +float4 SMAANeighborhoodBlendingPS(float2 texcoord, + float4 offset, + SMAATexture2D(colorTex), + SMAATexture2D(blendTex) + #if SMAA_REPROJECTION + , SMAATexture2D(velocityTex) + #endif + ) { + // Fetch the blending weights for current pixel: + float4 a; + a.x = SMAASample(blendTex, offset.xy).a; // Right + a.y = SMAASample(blendTex, offset.zw).g; // Top + a.wz = SMAASample(blendTex, texcoord).xz; // Bottom / Left + + // Is there any blending weight with a value greater than 0.0? + SMAA_BRANCH + if (dot(a, float4(1.0, 1.0, 1.0, 1.0)) < 1e-5) { + float4 color = SMAASampleLevelZero(colorTex, texcoord); + + #if SMAA_REPROJECTION + float2 velocity = SMAA_DECODE_VELOCITY(SMAASampleLevelZero(velocityTex, texcoord)); + #elif SMAA_UV_BASED_REPROJECTION + float2 velocity = texcoord - SMAAReproject(texcoord); + #endif + + #if (SMAA_REPROJECTION || SMAA_UV_BASED_REPROJECTION) + // Pack velocity into the alpha channel: + color.a = sqrt(5.0 * length(velocity)); + #endif + + return color; + } else { + bool h = max(a.x, a.z) > max(a.y, a.w); // max(horizontal) > max(vertical) + + // Calculate the blending offsets: + float4 blendingOffset = float4(0.0, a.y, 0.0, a.w); + float2 blendingWeight = a.yw; + SMAAMovc(bool4(h, h, h, h), blendingOffset, float4(a.x, 0.0, a.z, 0.0)); + SMAAMovc(bool2(h, h), blendingWeight, a.xz); + blendingWeight /= dot(blendingWeight, float2(1.0, 1.0)); + + // Calculate the texture coordinates: + float4 blendingCoord = mad(blendingOffset, float4(SMAA_RT_METRICS.xy, -SMAA_RT_METRICS.xy), texcoord.xyxy); + + // We exploit bilinear filtering to mix current pixel with the chosen + // neighbor: + float4 color = blendingWeight.x * SMAASampleLevelZero(colorTex, blendingCoord.xy); + color += blendingWeight.y * SMAASampleLevelZero(colorTex, blendingCoord.zw); + + #if SMAA_REPROJECTION + // Antialias velocity for proper reprojection in a later stage: + float2 velocity = blendingWeight.x * SMAA_DECODE_VELOCITY(SMAASampleLevelZero(velocityTex, blendingCoord.xy)); + velocity += blendingWeight.y * SMAA_DECODE_VELOCITY(SMAASampleLevelZero(velocityTex, blendingCoord.zw)); + #elif SMAA_UV_BASED_REPROJECTION + // Antialias velocity for proper reprojection in a later stage: + float2 velocity = blendingWeight.x * (blendingCoord.xy - SMAAReproject(blendingCoord.xy)); + velocity += blendingWeight.y * (blendingCoord.zw - SMAAReproject(blendingCoord.zw)); + #endif + + #if (SMAA_REPROJECTION || SMAA_UV_BASED_REPROJECTION) + // Pack velocity into the alpha channel: + color.a = sqrt(5.0 * length(velocity)); + #endif + + return color; + } +} + +//----------------------------------------------------------------------------- +// Temporal Resolve Pixel Shader (Optional Pass) + +float4 SMAAResolvePS(float2 texcoord, + SMAATexture2D(currentColorTex), + SMAATexture2D(previousColorTex) + #if SMAA_REPROJECTION + , SMAATexture2D(velocityTex) + #endif + ) { + #if SMAA_REPROJECTION + // Velocity is assumed to be calculated for motion blur, so we need to + // inverse it for reprojection: + float2 velocity = -SMAA_DECODE_VELOCITY(SMAASamplePoint(velocityTex, texcoord).rg); + #elif SMAA_UV_BASED_REPROJECTION + float2 velocity = SMAAReproject(texcoord) - texcoord; + #endif + + #if (SMAA_REPROJECTION || SMAA_UV_BASED_REPROJECTION) + // Fetch current pixel: + float4 current = SMAASamplePoint(currentColorTex, texcoord); + + // Reproject current coordinates and fetch previous pixel: + float4 previous = SMAASamplePoint(previousColorTex, texcoord + velocity); + + // Attenuate the previous pixel if the velocity is different: + float delta = abs(current.a * current.a - previous.a * previous.a) / 5.0; + float weight = 0.5 * saturate(1.0 - sqrt(delta) * SMAA_REPROJECTION_WEIGHT_SCALE); + + // Blend the pixels according to the calculated weight: + // return lerp(current, previous, weight); + + // Neighbour clamp + // Contributed by pommak + float4 n0 = SMAASampleOffset(currentColorTex, texcoord, float2(-1, -1)); + float4 n1 = SMAASampleOffset(currentColorTex, texcoord, float2(+1, -1)); + float4 n2 = SMAASampleOffset(currentColorTex, texcoord, float2(-1, +1)); + float4 n3 = SMAASampleOffset(currentColorTex, texcoord, float2(+1, +1)); + float4 cmax = max(n0, max(n1, max(n2, n3))); + float4 cmin = min(n0, min(n1, min(n2, n3))); + float4 avg = 0.25 * (n0+n1+n2+n3); + float4 wk = abs(avg - current); + float blend = saturate(lerp(0.35, 0.85, wk)); + + // Clamp previous to neighbours colors + float4 previousClamped = clamp(previous, cmin, cmax); + + float4 color = lerp(lerp(current, previousClamped, 0.5*weight), previousClamped, weight); + return color; + #else + // Just blend the pixels: + float4 current = SMAASamplePoint(currentColorTex, texcoord); + float4 previous = SMAASamplePoint(previousColorTex, texcoord); + return lerp(current, previous, 0.5); + #endif +} + +//----------------------------------------------------------------------------- +// Separate Multisamples Pixel Shader (Optional Pass) + +#ifdef SMAALoad +void SMAASeparatePS(float4 position, + float2 texcoord, + out float4 target0, + out float4 target1, + SMAATexture2DMS2(colorTexMS)) { + int2 pos = int2(position.xy); + target0 = SMAALoad(colorTexMS, pos, 0); + target1 = SMAALoad(colorTexMS, pos, 1); +} +#endif + +//----------------------------------------------------------------------------- +#endif // SMAA_INCLUDE_PS diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/SMAA/Resources/SMAA.cginc.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/SMAA/Resources/SMAA.cginc.meta new file mode 100644 index 0000000..184d013 --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/SMAA/Resources/SMAA.cginc.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 74597699f47d8ae458dca68f79f1b21f +timeCreated: 1430504573 +licenseType: Store +ShaderImporter: + defaultTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/SMAA/Resources/SMAA.shader b/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/SMAA/Resources/SMAA.shader new file mode 100644 index 0000000..fe37cec --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/SMAA/Resources/SMAA.shader @@ -0,0 +1,382 @@ +Shader "Hidden/Subpixel Morphological Anti-aliasing" +{ + Properties + { + _MainTex ("Base (RGB)", 2D) = "white" {} + } + + CGINCLUDE + + #pragma fragmentoption ARB_precision_hint_fastest + #pragma target 3.0 + #pragma glsl + #pragma exclude_renderers flash + + sampler2D _MainTex; + sampler2D _BlendTex; + sampler2D _AreaTex; + sampler2D _SearchTex; + sampler2D _AccumulationTex; + + sampler2D _CameraDepthTexture; + + float4 _MainTex_TexelSize; + + float4 _Metrics; // 1f / width, 1f / height, width, height + float4 _Params1; // SMAA_THRESHOLD, SMAA_DEPTH_THRESHOLD, SMAA_MAX_SEARCH_STEPS, SMAA_MAX_SEARCH_STEPS_DIAG + float2 _Params2; // SMAA_CORNER_ROUNDING, SMAA_LOCAL_CONTRAST_ADAPTATION_FACTOR + float3 _Params3; // SMAA_PREDICATION_THRESHOLD, SMAA_PREDICATION_SCALE, SMAA_PREDICATION_STRENGTH + + float4x4 _ReprojectionMatrix; + float4 _SubsampleIndices; + + #define SMAA_RT_METRICS _Metrics + #define SMAA_THRESHOLD _Params1.x + #define SMAA_DEPTH_THRESHOLD _Params1.y + #define SMAA_MAX_SEARCH_STEPS _Params1.z + #define SMAA_MAX_SEARCH_STEPS_DIAG _Params1.w + #define SMAA_CORNER_ROUNDING _Params2.x + #define SMAA_LOCAL_CONTRAST_ADAPTATION_FACTOR _Params2.y + #define SMAA_PREDICATION_THRESHOLD _Params3.x + #define SMAA_PREDICATION_SCALE _Params3.y + #define SMAA_PREDICATION_STRENGTH _Params3.z + + // Can't use SMAA_HLSL_3 as it won't compile with OpenGL, so lets make our own set of defines for Unity + #define SMAA_CUSTOM_SL + + #define mad(a, b, c) (a * b + c) + #define SMAATexture2D(tex) sampler2D tex + #define SMAATexturePass2D(tex) tex + #define SMAASampleLevelZero(tex, coord) tex2Dlod(tex, float4(coord, 0.0, 0.0)) + #define SMAASampleLevelZeroPoint(tex, coord) tex2Dlod(tex, float4(coord, 0.0, 0.0)) + #define SMAASampleLevelZeroOffset(tex, coord, offset) tex2Dlod(tex, float4(coord + offset * SMAA_RT_METRICS.xy, 0.0, 0.0)) + #define SMAASample(tex, coord) tex2D(tex, coord) + #define SMAASamplePoint(tex, coord) tex2D(tex, coord) + #define SMAASampleOffset(tex, coord, offset) tex2D(tex, coord + offset * SMAA_RT_METRICS.xy) + + #define SMAA_FLATTEN UNITY_FLATTEN + #define SMAA_BRANCH UNITY_BRANCH + // SMAA_CUSTOM_SL + + #define SMAA_AREATEX_SELECT(sample) sample.rg + #define SMAA_SEARCHTEX_SELECT(sample) sample.a + #define SMAA_INCLUDE_VS 0 + + struct vInput + { + float4 pos : POSITION; + float2 uv : TEXCOORD0; + }; + + struct fInput_edge + { + float4 pos : SV_POSITION; + float2 uv : TEXCOORD0; + float4 offset[3] : TEXCOORD1; + }; + + fInput_edge vert_edge(vInput i) + { + fInput_edge o; + o.pos = mul(UNITY_MATRIX_MVP, i.pos); + o.uv = i.uv; + + #if UNITY_UV_STARTS_AT_TOP + if (_MainTex_TexelSize.y < 0) + o.uv.y = 1.0 - i.uv.y; + #endif + + o.offset[0] = mad(SMAA_RT_METRICS.xyxy, float4(-1.0, 0.0, 0.0, -1.0), o.uv.xyxy); + o.offset[1] = mad(SMAA_RT_METRICS.xyxy, float4( 1.0, 0.0, 0.0, 1.0), o.uv.xyxy); + o.offset[2] = mad(SMAA_RT_METRICS.xyxy, float4(-2.0, 0.0, 0.0, -2.0), o.uv.xyxy); + return o; + } + + ENDCG + + SubShader + { + ZTest Always Cull Off ZWrite Off + Fog { Mode off } + + // (0) Clear + Pass + { + CGPROGRAM + + #pragma vertex vert_img + #pragma fragment frag + #include "UnityCG.cginc" + + float4 frag(v2f_img i) : SV_Target + { + return float4(0.0, 0.0, 0.0, 0.0); + } + + ENDCG + } + + + // ----------------------------------------------------------------------------- + // Edge Detection + + // (1) Luma + Pass + { + // TODO: Stencil not working + // Stencil + // { + // Pass replace + // Ref 1 + // } + + CGPROGRAM + + #pragma vertex vert_edge + #pragma fragment frag + #pragma multi_compile __ USE_PREDICATION + + #if USE_PREDICATION + #define SMAA_PREDICATION 1 + #else + #define SMAA_PREDICATION 0 + #endif + + #include "UnityCG.cginc" + #include "SMAA.cginc" + + float4 frag(fInput_edge i) : SV_Target + { + #if SMAA_PREDICATION + return float4(SMAALumaEdgeDetectionPS(i.uv, i.offset, _MainTex, _CameraDepthTexture), 0.0, 0.0); + #else + return float4(SMAALumaEdgeDetectionPS(i.uv, i.offset, _MainTex), 0.0, 0.0); + #endif + } + + ENDCG + } + + // (2) Color + Pass + { + // TODO: Stencil not working + // Stencil + // { + // Pass replace + // Ref 1 + // } + + CGPROGRAM + + #pragma vertex vert_edge + #pragma fragment frag + #pragma multi_compile __ USE_PREDICATION + + #if USE_PREDICATION + #define SMAA_PREDICATION 1 + #else + #define SMAA_PREDICATION 0 + #endif + + #include "UnityCG.cginc" + #include "SMAA.cginc" + + float4 frag(fInput_edge i) : SV_Target + { + #if SMAA_PREDICATION + return float4(SMAAColorEdgeDetectionPS(i.uv, i.offset, _MainTex, _CameraDepthTexture), 0.0, 0.0); + #else + return float4(SMAAColorEdgeDetectionPS(i.uv, i.offset, _MainTex), 0.0, 0.0); + #endif + } + + ENDCG + } + + // (3) Depth + Pass + { + // TODO: Stencil not working + // Stencil + // { + // Pass replace + // Ref 1 + // } + + CGPROGRAM + + #pragma vertex vert_edge + #pragma fragment frag + + #define SMAA_PREDICATION 0 + + #include "UnityCG.cginc" + #include "SMAA.cginc" + + float4 frag(fInput_edge i) : SV_Target + { + return float4(SMAADepthEdgeDetectionPS(i.uv, i.offset, _CameraDepthTexture), 0.0, 0.0); + } + + ENDCG + } + + + // ----------------------------------------------------------------------------- + // Blend Weights Calculation + + // (4) + Pass + { + // TODO: Stencil not working + // Stencil + // { + // Pass keep + // Comp equal + // Ref 1 + // } + + CGPROGRAM + + #pragma vertex vert + #pragma fragment frag + #pragma multi_compile __ USE_DIAG_SEARCH + #pragma multi_compile __ USE_CORNER_DETECTION + + #if !defined(USE_DIAG_SEARCH) + #define SMAA_DISABLE_DIAG_DETECTION + #endif + + #if !defined(USE_CORNER_DETECTION) + #define SMAA_DISABLE_CORNER_DETECTION + #endif + + #include "UnityCG.cginc" + #include "SMAA.cginc" + + struct fInput + { + float4 pos : SV_POSITION; + float2 uv : TEXCOORD0; + float2 pixcoord : TEXCOORD1; + float4 offset[3] : TEXCOORD2; + }; + + fInput vert(vInput i) + { + fInput o; + o.pos = mul(UNITY_MATRIX_MVP, i.pos); + o.uv = i.uv; + o.pixcoord = o.uv * SMAA_RT_METRICS.zw; + + // We will use these offsets for the searches later on (see @PSEUDO_GATHER4): + o.offset[0] = mad(SMAA_RT_METRICS.xyxy, float4(-0.25, -0.125, 1.25, -0.125), o.uv.xyxy); + o.offset[1] = mad(SMAA_RT_METRICS.xyxy, float4(-0.125, -0.25, -0.125, 1.25), o.uv.xyxy); + + // And these for the searches, they indicate the ends of the loops: + o.offset[2] = mad(SMAA_RT_METRICS.xxyy, float4(-2.0, 2.0, -2.0, 2.0) * float(SMAA_MAX_SEARCH_STEPS), + float4(o.offset[0].xz, o.offset[1].yw)); + + return o; + } + + float4 frag(fInput i) : SV_Target + { + return SMAABlendingWeightCalculationPS(i.uv, i.pixcoord, i.offset, _MainTex, _AreaTex, _SearchTex, + _SubsampleIndices); + } + + ENDCG + } + + + // ----------------------------------------------------------------------------- + // Neighborhood Blending + + // (5) + Pass + { + CGPROGRAM + + #pragma vertex vert + #pragma fragment frag + + #pragma multi_compile __ USE_UV_BASED_REPROJECTION + + #if defined (USE_UV_BASED_REPROJECTION) + #define SMAA_UV_BASED_REPROJECTION 1 + #endif + + #include "UnityCG.cginc" + #include "SMAA.cginc" + + struct fInput + { + float4 pos : SV_POSITION; + float2 uv : TEXCOORD0; + float4 offset : TEXCOORD1; + }; + + fInput vert(vInput i) + { + fInput o; + o.pos = mul(UNITY_MATRIX_MVP, i.pos); + o.uv = i.uv; + o.offset = mad(SMAA_RT_METRICS.xyxy, float4(1.0, 0.0, 0.0, 1.0), o.uv.xyxy); + return o; + } + + float4 frag(fInput i) : SV_Target + { + return SMAANeighborhoodBlendingPS(i.uv, i.offset, _MainTex, _BlendTex); + } + + ENDCG + } + + // ----------------------------------------------------------------------------- + // Accumulation Resolve + + // (6) + Pass + { + CGPROGRAM + + #pragma vertex vert + #pragma fragment frag + + #pragma multi_compile __ USE_UV_BASED_REPROJECTION + + #if defined (USE_UV_BASED_REPROJECTION) + #define SMAA_UV_BASED_REPROJECTION 1 + #endif + + #include "UnityCG.cginc" + #include "SMAA.cginc" + + struct fInput + { + float4 pos : SV_POSITION; + float2 uv : TEXCOORD0; + }; + + fInput vert(vInput i) + { + fInput o; + o.pos = mul(UNITY_MATRIX_MVP, i.pos); + o.uv = i.uv; + return o; + } + + float4 frag(fInput i) : SV_Target + { + return SMAAResolvePS(i.uv, _MainTex, _AccumulationTex); + } + + ENDCG + } + } + + FallBack off +} diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/SMAA/Resources/SMAA.shader.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/SMAA/Resources/SMAA.shader.meta new file mode 100644 index 0000000..931b06f --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/SMAA/Resources/SMAA.shader.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 4505fec7a81214243b8e59edf89e3a53 +timeCreated: 1432603500 +licenseType: Store +ShaderImporter: + defaultTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/SMAA/Resources/SearchTex.tga b/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/SMAA/Resources/SearchTex.tga new file mode 100644 index 0000000000000000000000000000000000000000..bda78d05316a4e9985444fafd51b951b5f0e847c GIT binary patch literal 3116 zcmeH_T?)c55QG;`;G>t&Gx$;=APWBBZM?Y{8v3zK#?n4i6qA=uW_PC3p=Jx~&eoQ; zvS)iD_h?TVO0v`So~QucDv{AGf}X7Zx@J( z)oCXqXYF4`mE?Ekm#HfGu?Dh#HN97oGLqcPNUq*Nl73+%#s?6EV8A;!767H(kMNNs z)BgeV04NI_Xag0Xl=~4@l4Lp_-~%WF47i~JlyX19N|H<~s14KxrZjLlU7K4thvQ*= J--Ug%u@~rm5lH|5 literal 0 HcmV?d00001 diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/SMAA/Resources/SearchTex.tga.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/SMAA/Resources/SearchTex.tga.meta new file mode 100644 index 0000000..637bc38 --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/SMAA/Resources/SearchTex.tga.meta @@ -0,0 +1,57 @@ +fileFormatVersion: 2 +guid: 387ed7c38eb63554db846987adb98e68 +timeCreated: 1432601000 +licenseType: Store +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + linearTexture: 1 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 1 + generateCubemap: 0 + cubemapConvolution: 0 + cubemapConvolutionSteps: 8 + cubemapConvolutionExponent: 1.5 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + filterMode: 0 + aniso: -1 + mipBias: -1 + wrapMode: 1 + nPOTScale: 0 + lightmap: 0 + rGBM: 2 + compressionQuality: 50 + allowsAlphaSplitting: 0 + 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 + alphaIsTransparency: 0 + textureType: 5 + buildTargetSettings: [] + spriteSheet: + sprites: [] + outline: [] + spritePackingTag: + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/SMAA/SMAA.cs b/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/SMAA/SMAA.cs new file mode 100644 index 0000000..63328fc --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/SMAA/SMAA.cs @@ -0,0 +1,484 @@ +using UnityEngine; +using System; +#if UNITY_EDITOR +using UnityEditor; +#endif +using Object = UnityEngine.Object; + +namespace UnityStandardAssets.CinematicEffects +{ + [Serializable] + public class SMAA : IAntiAliasing + { + [AttributeUsage(AttributeTargets.Field)] + public class SettingsGroup : Attribute + {} + + [AttributeUsage(AttributeTargets.Field)] + public class TopLevelSettings : Attribute + {} + + [AttributeUsage(AttributeTargets.Field)] + public class ExperimentalGroup : Attribute + {} + + public enum DebugPass + { + Off, + Edges, + Weights, + Accumulation + } + + public enum QualityPreset + { + Low = 0, + Medium = 1, + High = 2, + Ultra = 3, + Custom + } + + public enum EdgeDetectionMethod + { + Luma = 1, + Color = 2, + Depth = 3 + } + + [Serializable] + public struct GlobalSettings + { + [Tooltip("Use this to fine tune your settings when working in Custom quality mode. \"Accumulation\" only works when \"Temporal Filtering\" is enabled.")] + public DebugPass debugPass; + + [Tooltip("Low: 60% of the quality.\nMedium: 80% of the quality.\nHigh: 95% of the quality.\nUltra: 99% of the quality (overkill).")] + public QualityPreset quality; + + [Tooltip("You've three edge detection methods to choose from: luma, color or depth.\nThey represent different quality/performance and anti-aliasing/sharpness tradeoffs, so our recommendation is for you to choose the one that best suits your particular scenario:\n\n- Depth edge detection is usually the fastest but it may miss some edges.\n- Luma edge detection is usually more expensive than depth edge detection, but catches visible edges that depth edge detection can miss.\n- Color edge detection is usually the most expensive one but catches chroma-only edges.")] + public EdgeDetectionMethod edgeDetectionMethod; + + public static GlobalSettings defaultSettings + { + get + { + return new GlobalSettings + { + debugPass = DebugPass.Off, + quality = QualityPreset.High, + edgeDetectionMethod = EdgeDetectionMethod.Color + }; + } + } + } + + [Serializable] + public struct QualitySettings + { + [Tooltip("Enables/Disables diagonal processing.")] + public bool diagonalDetection; + + [Tooltip("Enables/Disables corner detection. Leave this on to avoid blurry corners.")] + public bool cornerDetection; + + [Range(0f, 0.5f)] + [Tooltip("Specifies the threshold or sensitivity to edges. Lowering this value you will be able to detect more edges at the expense of performance.\n0.1 is a reasonable value, and allows to catch most visible edges. 0.05 is a rather overkill value, that allows to catch 'em all.")] + public float threshold; + + [Min(0.0001f)] + [Tooltip("Specifies the threshold for depth edge detection. Lowering this value you will be able to detect more edges at the expense of performance.")] + public float depthThreshold; + + [Range(0, 112)] + [Tooltip("Specifies the maximum steps performed in the horizontal/vertical pattern searches, at each side of the pixel.\nIn number of pixels, it's actually the double. So the maximum line length perfectly handled by, for example 16, is 64 (by perfectly, we meant that longer lines won't look as good, but still antialiased).")] + public int maxSearchSteps; + + [Range(0, 20)] + [Tooltip("Specifies the maximum steps performed in the diagonal pattern searches, at each side of the pixel. In this case we jump one pixel at time, instead of two.\nOn high-end machines it is cheap (between a 0.8x and 0.9x slower for 16 steps), but it can have a significant impact on older machines.")] + public int maxDiagonalSearchSteps; + + [Range(0, 100)] + [Tooltip("Specifies how much sharp corners will be rounded.")] + public int cornerRounding; + + [Min(0f)] + [Tooltip("If there is an neighbor edge that has a local contrast factor times bigger contrast than current edge, current edge will be discarded.\nThis allows to eliminate spurious crossing edges, and is based on the fact that, if there is too much contrast in a direction, that will hide perceptually contrast in the other neighbors.")] + public float localContrastAdaptationFactor; + + public static QualitySettings[] presetQualitySettings = + { + // Low + new QualitySettings + { + diagonalDetection = false, + cornerDetection = false, + threshold = 0.15f, + depthThreshold = 0.01f, + maxSearchSteps = 4, + maxDiagonalSearchSteps = 8, + cornerRounding = 25, + localContrastAdaptationFactor = 2f + }, + + // Medium + new QualitySettings + { + diagonalDetection = false, + cornerDetection = false, + threshold = 0.1f, + depthThreshold = 0.01f, + maxSearchSteps = 8, + maxDiagonalSearchSteps = 8, + cornerRounding = 25, + localContrastAdaptationFactor = 2f + }, + + // High + new QualitySettings + { + diagonalDetection = true, + cornerDetection = true, + threshold = 0.1f, + depthThreshold = 0.01f, + maxSearchSteps = 16, + maxDiagonalSearchSteps = 8, + cornerRounding = 25, + localContrastAdaptationFactor = 2f + }, + + // Ultra + new QualitySettings + { + diagonalDetection = true, + cornerDetection = true, + threshold = 0.05f, + depthThreshold = 0.01f, + maxSearchSteps = 32, + maxDiagonalSearchSteps = 16, + cornerRounding = 25, + localContrastAdaptationFactor = 2f + }, + }; + } + + [Serializable] + public struct TemporalSettings + { + [Tooltip("Temporal filtering makes it possible for the SMAA algorithm to benefit from minute subpixel information available that has been accumulated over many frames.")] + public bool enabled; + + public bool UseTemporal() + { +#if UNITY_EDITOR + return enabled && EditorApplication.isPlayingOrWillChangePlaymode; +#else + return enabled; +#endif + } + + [Range(0.5f, 10.0f)] + [Tooltip("The size of the fuzz-displacement (jitter) in pixels applied to the camera's perspective projection matrix.\nUsed for 2x temporal anti-aliasing.")] + public float fuzzSize; + + public static TemporalSettings defaultSettings + { + get + { + return new TemporalSettings + { + enabled = false, + fuzzSize = 2f + }; + } + } + } + + [Serializable] + public struct PredicationSettings + { + [Tooltip("Predicated thresholding allows to better preserve texture details and to improve performance, by decreasing the number of detected edges using an additional buffer (the detph buffer).\nIt locally decreases the luma or color threshold if an edge is found in an additional buffer (so the global threshold can be higher).")] + public bool enabled; + + [Min(0.0001f)] + [Tooltip("Threshold to be used in the additional predication buffer.")] + public float threshold; + + [Range(1f, 5f)] + [Tooltip("How much to scale the global threshold used for luma or color edge detection when using predication.")] + public float scale; + + [Range(0f, 1f)] + [Tooltip("How much to locally decrease the threshold.")] + public float strength; + + public static PredicationSettings defaultSettings + { + get + { + return new PredicationSettings + { + enabled = false, + threshold = 0.01f, + scale = 2f, + strength = 0.4f + }; + } + } + } + + [TopLevelSettings] + public GlobalSettings settings = GlobalSettings.defaultSettings; + + [SettingsGroup] + public QualitySettings quality = QualitySettings.presetQualitySettings[2]; + + [SettingsGroup] + public PredicationSettings predication = PredicationSettings.defaultSettings; + + [SettingsGroup, ExperimentalGroup] + public TemporalSettings temporal = TemporalSettings.defaultSettings; + + private Matrix4x4 m_ProjectionMatrix; + private Matrix4x4 m_PreviousViewProjectionMatrix; + private float m_FlipFlop = 1.0f; + private RenderTexture m_Accumulation; + + private Shader m_Shader; + public Shader shader + { + get + { + if (m_Shader == null) + m_Shader = Shader.Find("Hidden/Subpixel Morphological Anti-aliasing"); + + return m_Shader; + } + } + + private Texture2D m_AreaTexture; + private Texture2D areaTexture + { + get + { + if (m_AreaTexture == null) + m_AreaTexture = Resources.Load("AreaTex"); + return m_AreaTexture; + } + } + + private Texture2D m_SearchTexture; + private Texture2D searchTexture + { + get + { + if (m_SearchTexture == null) + m_SearchTexture = Resources.Load("SearchTex"); + return m_SearchTexture; + } + } + + private Material m_Material; + private Material material + { + get + { + if (m_Material == null) + m_Material = ImageEffectHelper.CheckShaderAndCreateMaterial(shader); + + return m_Material; + } + } + + public void OnEnable(AntiAliasing owner) + { + if (!ImageEffectHelper.IsSupported(shader, true, false, owner)) + owner.enabled = false; + } + + public void OnDisable() + { + // Cleanup + if (m_Material != null) + Object.DestroyImmediate(m_Material); + + if (m_Accumulation != null) + Object.DestroyImmediate(m_Accumulation); + + m_Material = null; + m_Accumulation = null; + } + + public void OnPreCull(Camera camera) + { + if (temporal.UseTemporal()) + { + m_ProjectionMatrix = camera.projectionMatrix; + m_FlipFlop -= (2.0f * m_FlipFlop); + + Matrix4x4 fuzz = Matrix4x4.identity; + + fuzz.m03 = (0.25f * m_FlipFlop) * temporal.fuzzSize / camera.pixelWidth; + fuzz.m13 = (-0.25f * m_FlipFlop) * temporal.fuzzSize / camera.pixelHeight; + + camera.projectionMatrix = fuzz * camera.projectionMatrix; + } + } + + public void OnPostRender(Camera camera) + { + if (temporal.UseTemporal()) + camera.ResetProjectionMatrix(); + } + + public void OnRenderImage(Camera camera, RenderTexture source, RenderTexture destination) + { + int width = camera.pixelWidth; + int height = camera.pixelHeight; + + bool isFirstFrame = false; + + QualitySettings preset = quality; + + if (settings.quality != QualityPreset.Custom) + preset = QualitySettings.presetQualitySettings[(int)settings.quality]; + + // Pass IDs + int passEdgeDetection = (int)settings.edgeDetectionMethod; + int passBlendWeights = 4; + int passNeighborhoodBlending = 5; + int passResolve = 6; + + // Reprojection setup + var viewProjectionMatrix = GL.GetGPUProjectionMatrix(m_ProjectionMatrix, true) * camera.worldToCameraMatrix; + + // Uniforms + material.SetTexture("_AreaTex", areaTexture); + material.SetTexture("_SearchTex", searchTexture); + + material.SetVector("_Metrics", new Vector4(1f / width, 1f / height, width, height)); + material.SetVector("_Params1", new Vector4(preset.threshold, preset.depthThreshold, preset.maxSearchSteps, preset.maxDiagonalSearchSteps)); + material.SetVector("_Params2", new Vector2(preset.cornerRounding, preset.localContrastAdaptationFactor)); + + material.SetMatrix("_ReprojectionMatrix", m_PreviousViewProjectionMatrix * Matrix4x4.Inverse(viewProjectionMatrix)); + + float subsampleIndex = (m_FlipFlop < 0.0f) ? 2.0f : 1.0f; + material.SetVector("_SubsampleIndices", new Vector4(subsampleIndex, subsampleIndex, subsampleIndex, 0.0f)); + + // Handle predication & depth-based edge detection + Shader.DisableKeyword("USE_PREDICATION"); + + if (settings.edgeDetectionMethod == EdgeDetectionMethod.Depth) + { + camera.depthTextureMode |= DepthTextureMode.Depth; + } + else if (predication.enabled) + { + camera.depthTextureMode |= DepthTextureMode.Depth; + Shader.EnableKeyword("USE_PREDICATION"); + material.SetVector("_Params3", new Vector3(predication.threshold, predication.scale, predication.strength)); + } + + // Diag search & corner detection + Shader.DisableKeyword("USE_DIAG_SEARCH"); + Shader.DisableKeyword("USE_CORNER_DETECTION"); + + if (preset.diagonalDetection) + Shader.EnableKeyword("USE_DIAG_SEARCH"); + + if (preset.cornerDetection) + Shader.EnableKeyword("USE_CORNER_DETECTION"); + + // UV-based reprojection (up to Unity 5.x) + // TODO: use motion vectors when available! + Shader.DisableKeyword("USE_UV_BASED_REPROJECTION"); + + if (temporal.UseTemporal()) + Shader.EnableKeyword("USE_UV_BASED_REPROJECTION"); + + // Persistent textures and lazy-initializations + if (m_Accumulation == null || (m_Accumulation.width != width || m_Accumulation.height != height)) + { + if (m_Accumulation) + RenderTexture.ReleaseTemporary(m_Accumulation); + + m_Accumulation = RenderTexture.GetTemporary(width, height, 0, source.format, RenderTextureReadWrite.Linear); + m_Accumulation.hideFlags = HideFlags.HideAndDontSave; + + isFirstFrame = true; + } + + RenderTexture rt1 = TempRT(width, height, source.format); + Graphics.Blit(null, rt1, material, 0); // Clear + + // Edge Detection + Graphics.Blit(source, rt1, material, passEdgeDetection); + + if (settings.debugPass == DebugPass.Edges) + { + Graphics.Blit(rt1, destination); + } + else + { + RenderTexture rt2 = TempRT(width, height, source.format); + Graphics.Blit(null, rt2, material, 0); // Clear + + // Blend Weights + Graphics.Blit(rt1, rt2, material, passBlendWeights); + + if (settings.debugPass == DebugPass.Weights) + { + Graphics.Blit(rt2, destination); + } + else + { + // Neighborhood Blending + material.SetTexture("_BlendTex", rt2); + + if (temporal.UseTemporal()) + { + // Temporal filtering + Graphics.Blit(source, rt1, material, passNeighborhoodBlending); + + if (settings.debugPass == DebugPass.Accumulation) + { + Graphics.Blit(m_Accumulation, destination); + } + else if (!isFirstFrame) + { + material.SetTexture("_AccumulationTex", m_Accumulation); + Graphics.Blit(rt1, destination, material, passResolve); + } + else + { + Graphics.Blit(rt1, destination); + } + + //Graphics.Blit(rt1, m_Accumulation); + Graphics.Blit(destination, m_Accumulation); + RenderTexture.active = null; + } + else + { + Graphics.Blit(source, destination, material, passNeighborhoodBlending); + } + } + + RenderTexture.ReleaseTemporary(rt2); + } + + RenderTexture.ReleaseTemporary(rt1); + + // Store the future-previous frame's view-projection matrix + m_PreviousViewProjectionMatrix = viewProjectionMatrix; + } + + private RenderTexture TempRT(int width, int height, RenderTextureFormat format) + { + // Skip the depth & stencil buffer creation when DebugPass is set to avoid flickering + // TODO: Stencil buffer not working for some reason + // int depthStencilBits = DebugPass == DebugPass.Off ? 24 : 0; + int depthStencilBits = 0; + return RenderTexture.GetTemporary(width, height, depthStencilBits, format, RenderTextureReadWrite.Linear); + } + } +} diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/SMAA/SMAA.cs.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/SMAA/SMAA.cs.meta new file mode 100644 index 0000000..48dccc5 --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/SMAA/SMAA.cs.meta @@ -0,0 +1,13 @@ +fileFormatVersion: 2 +guid: 9c2502951f8f3e743917c441eba57d1c +timeCreated: 1454511067 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: + - m_Shader: {fileID: 4800000, guid: 4505fec7a81214243b8e59edf89e3a53, type: 3} + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/Bloom.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/Bloom.meta new file mode 100644 index 0000000..599b855 --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/Bloom.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 193f90bb87f484c62ad73788d9cb2d44 +folderAsset: yes +timeCreated: 1454052266 +licenseType: Store +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/Bloom/Bloom.cs b/IronToad_UnityProject/Assets/Standard Assets/Effects/Bloom/Bloom.cs new file mode 100644 index 0000000..596843c --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/Bloom/Bloom.cs @@ -0,0 +1,205 @@ +using System; +using UnityEngine; + +namespace UnityStandardAssets.CinematicEffects +{ + [ExecuteInEditMode] + [RequireComponent(typeof(Camera))] + [AddComponentMenu("Image Effects/Cinematic/Bloom")] +#if UNITY_5_4_OR_NEWER + [ImageEffectAllowedInSceneView] +#endif + public class Bloom : MonoBehaviour + { + [Serializable] + public struct Settings + { + [SerializeField] + [Tooltip("Filters out pixels under this level of brightness.")] + public float threshold; + + public float thresholdGamma + { + set { threshold = value; } + get { return Mathf.Max(0.0f, threshold); } + } + + public float thresholdLinear + { + set { threshold = Mathf.LinearToGammaSpace(value); } + get { return Mathf.GammaToLinearSpace(thresholdGamma); } + } + + [SerializeField, Range(0, 1)] + [Tooltip("Makes transition between under/over-threshold gradual.")] + public float softKnee; + + [SerializeField, Range(1, 7)] + [Tooltip("Changes extent of veiling effects in a screen resolution-independent fashion.")] + public float radius; + + [SerializeField] + [Tooltip("Blend factor of the result image.")] + public float intensity; + + [SerializeField] + [Tooltip("Controls filter quality and buffer resolution.")] + public bool highQuality; + + [SerializeField] + [Tooltip("Reduces flashing noise with an additional filter.")] + public bool antiFlicker; + + public static Settings defaultSettings + { + get + { + var settings = new Settings + { + threshold = 0.9f, + softKnee = 0.5f, + radius = 2.0f, + intensity = 0.7f, + highQuality = true, + antiFlicker = false + }; + return settings; + } + } + } + + #region Public Properties + + [SerializeField] + public Settings settings = Settings.defaultSettings; + + #endregion + + [SerializeField, HideInInspector] + private Shader m_Shader; + + public Shader shader + { + get + { + if (m_Shader == null) + { + const string shaderName = "Hidden/Image Effects/Cinematic/Bloom"; + m_Shader = Shader.Find(shaderName); + } + + return m_Shader; + } + } + + private Material m_Material; + public Material material + { + get + { + if (m_Material == null) + m_Material = ImageEffectHelper.CheckShaderAndCreateMaterial(shader); + + return m_Material; + } + } + + #region Private Members + + const int kMaxIterations = 16; + RenderTexture[] m_blurBuffer1 = new RenderTexture[kMaxIterations]; + RenderTexture[] m_blurBuffer2 = new RenderTexture[kMaxIterations]; + + private void OnEnable() + { + if (!ImageEffectHelper.IsSupported(shader, true, false, this)) + enabled = false; + } + + private void OnDisable() + { + if (m_Material != null) + DestroyImmediate(m_Material); + + m_Material = null; + } + + private void OnRenderImage(RenderTexture source, RenderTexture destination) + { + var useRGBM = Application.isMobilePlatform; + + // source texture size + var tw = source.width; + var th = source.height; + + // halve the texture size for the low quality mode + if (!settings.highQuality) + { + tw /= 2; + th /= 2; + } + + // blur buffer format + var rtFormat = useRGBM ? RenderTextureFormat.Default : RenderTextureFormat.DefaultHDR; + + // determine the iteration count + var logh = Mathf.Log(th, 2) + settings.radius - 8; + var logh_i = (int)logh; + var iterations = Mathf.Clamp(logh_i, 1, kMaxIterations); + + // update the shader properties + var threshold = settings.thresholdLinear; + material.SetFloat("_Threshold", threshold); + + var knee = threshold * settings.softKnee + 1e-5f; + var curve = new Vector3(threshold - knee, knee * 2, 0.25f / knee); + material.SetVector("_Curve", curve); + + var pfo = !settings.highQuality && settings.antiFlicker; + material.SetFloat("_PrefilterOffs", pfo ? -0.5f : 0.0f); + + material.SetFloat("_SampleScale", 0.5f + logh - logh_i); + material.SetFloat("_Intensity", Mathf.Max(0.0f, settings.intensity)); + + // prefilter pass + var prefiltered = RenderTexture.GetTemporary(tw, th, 0, rtFormat); + Graphics.Blit(source, prefiltered, material, settings.antiFlicker ? 1 : 0); + + // construct a mip pyramid + var last = prefiltered; + for (var level = 0; level < iterations; level++) + { + m_blurBuffer1[level] = RenderTexture.GetTemporary(last.width / 2, last.height / 2, 0, rtFormat); + Graphics.Blit(last, m_blurBuffer1[level], material, level == 0 ? (settings.antiFlicker ? 3 : 2) : 4); + last = m_blurBuffer1[level]; + } + + // upsample and combine loop + for (var level = iterations - 2; level >= 0; level--) + { + var basetex = m_blurBuffer1[level]; + material.SetTexture("_BaseTex", basetex); + m_blurBuffer2[level] = RenderTexture.GetTemporary(basetex.width, basetex.height, 0, rtFormat); + Graphics.Blit(last, m_blurBuffer2[level], material, settings.highQuality ? 6 : 5); + last = m_blurBuffer2[level]; + } + + // finish process + material.SetTexture("_BaseTex", source); + Graphics.Blit(last, destination, material, settings.highQuality ? 8 : 7); + + // release the temporary buffers + for (var i = 0; i < kMaxIterations; i++) + { + if (m_blurBuffer1[i] != null) RenderTexture.ReleaseTemporary(m_blurBuffer1[i]); + if (m_blurBuffer2[i] != null) RenderTexture.ReleaseTemporary(m_blurBuffer2[i]); + m_blurBuffer1[i] = null; + m_blurBuffer2[i] = null; + } + + RenderTexture.ReleaseTemporary(prefiltered); + } + + #endregion + } +} diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/Bloom/Bloom.cs.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/Bloom/Bloom.cs.meta new file mode 100644 index 0000000..fa96e0a --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/Bloom/Bloom.cs.meta @@ -0,0 +1,13 @@ +fileFormatVersion: 2 +guid: 32187365ced0c42219cde2b57c99b323 +timeCreated: 1454052338 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: + - _shader: {fileID: 4800000, guid: e45d4f28262b04d10a075856ab5fdb5e, type: 3} + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/Bloom/Editor.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/Bloom/Editor.meta new file mode 100644 index 0000000..73fe404 --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/Bloom/Editor.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 92a024b1f1430409eb656f65969aa3d5 +folderAsset: yes +timeCreated: 1454052266 +licenseType: Store +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/Bloom/Editor/BloomEditor.cs b/IronToad_UnityProject/Assets/Standard Assets/Effects/Bloom/Editor/BloomEditor.cs new file mode 100644 index 0000000..183ca3e --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/Bloom/Editor/BloomEditor.cs @@ -0,0 +1,54 @@ +using System; +using System.Collections.Generic; +using UnityEngine; +using UnityEditor; + +namespace UnityStandardAssets.CinematicEffects +{ + [CanEditMultipleObjects] + [CustomEditor(typeof(Bloom))] + public class BloomEditor : Editor + { + [NonSerialized] + private List m_Properties = new List(); + + BloomGraphDrawer _graph; + + bool CheckHdr(Bloom target) + { + var camera = target.GetComponent(); + return camera != null && camera.hdr; + } + + void OnEnable() + { + var settings = FieldFinder.GetField(x => x.settings); + foreach (var setting in settings.FieldType.GetFields()) + { + var prop = settings.Name + "." + setting.Name; + m_Properties.Add(serializedObject.FindProperty(prop)); + } + + _graph = new BloomGraphDrawer(); + } + + public override void OnInspectorGUI() + { + serializedObject.Update(); + + if (!serializedObject.isEditingMultipleObjects) + { + EditorGUILayout.Space(); + var bloom = (Bloom)target; + _graph.Prepare(bloom.settings, CheckHdr(bloom)); + _graph.DrawGraph(); + EditorGUILayout.Space(); + } + + foreach (var property in m_Properties) + EditorGUILayout.PropertyField(property); + + serializedObject.ApplyModifiedProperties(); + } + } +} diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/Bloom/Editor/BloomEditor.cs.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/Bloom/Editor/BloomEditor.cs.meta new file mode 100644 index 0000000..8f01ef2 --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/Bloom/Editor/BloomEditor.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 38020a6029a85434a95a6f725a5aae5f +timeCreated: 1454052266 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/Bloom/Editor/BloomGraphDrawer.cs b/IronToad_UnityProject/Assets/Standard Assets/Effects/Bloom/Editor/BloomGraphDrawer.cs new file mode 100644 index 0000000..c8f1522 --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/Bloom/Editor/BloomGraphDrawer.cs @@ -0,0 +1,156 @@ +using UnityEngine; +using UnityEditor; + +namespace UnityStandardAssets.CinematicEffects +{ + // Class used for drawing the brightness response curve + public class BloomGraphDrawer + { + #region Public Methods + + // Update internal state from given settings. + public void Prepare(Bloom.Settings settings, bool isHdr) + { + if (isHdr) + { + _rangeX = 6; + _rangeY = 1.5f; + } + else + { + _rangeX = 1; + _rangeY = 1; + } + + _threshold = settings.thresholdLinear; + _knee = settings.softKnee * _threshold + 1e-5f; + + // Intensity is capped to prevent sampling errors. + _intensity = Mathf.Min(settings.intensity, 10); + } + + // Draw the graph at the current position. + public void DrawGraph() + { + _rectGraph = GUILayoutUtility.GetRect(128, 80); + + // Background + DrawRect(0, 0, _rangeX, _rangeY, 0.1f, 0.4f); + + // Soft-knee range + DrawRect(_threshold - _knee, 0, _threshold + _knee, _rangeY, 0.25f, -1); + + // Horizontal lines + for (var i = 1; i < _rangeY; i++) + DrawLine(0, i, _rangeX, i, 0.4f); + + // Vertical lines + for (var i = 1; i < _rangeX; i++) + DrawLine(i, 0, i, _rangeY, 0.4f); + + // Label + Handles.Label( + PointInRect(0, _rangeY) + Vector3.right, + "Brightness Response (linear)", EditorStyles.miniLabel + ); + + // Threshold line + DrawLine(_threshold, 0, _threshold, _rangeY, 0.6f); + + // Response curve + var vcount = 0; + while (vcount < _curveResolution) + { + var x = _rangeX * vcount / (_curveResolution - 1); + var y = ResponseFunction(x); + if (y < _rangeY) + { + _curveVertices[vcount++] = PointInRect(x, y); + } + else + { + if (vcount > 1) + { + // Extend the last segment to the top edge of the rect. + var v1 = _curveVertices[vcount - 2]; + var v2 = _curveVertices[vcount - 1]; + var clip = (_rectGraph.y - v1.y) / (v2.y - v1.y); + _curveVertices[vcount - 1] = v1 + (v2 - v1) * clip; + } + break; + } + } + + if (vcount > 1) + { + Handles.color = Color.white * 0.9f; + Handles.DrawAAPolyLine(2.0f, vcount, _curveVertices); + } + } + + #endregion + + #region Response Function + + float _threshold; + float _knee; + float _intensity; + + float ResponseFunction(float x) + { + var rq = Mathf.Clamp(x - _threshold + _knee, 0, _knee * 2); + rq = rq * rq * 0.25f / _knee; + return Mathf.Max(rq, x - _threshold) * _intensity; + } + + #endregion + + #region Graph Functions + + // Number of vertices in curve + const int _curveResolution = 96; + + // Vertex buffers + Vector3[] _rectVertices = new Vector3[4]; + Vector3[] _lineVertices = new Vector3[2]; + Vector3[] _curveVertices = new Vector3[_curveResolution]; + + Rect _rectGraph; + float _rangeX; + float _rangeY; + + // Transform a point into the graph rect. + Vector3 PointInRect(float x, float y) + { + x = Mathf.Lerp(_rectGraph.x, _rectGraph.xMax, x / _rangeX); + y = Mathf.Lerp(_rectGraph.yMax, _rectGraph.y, y / _rangeY); + return new Vector3(x, y, 0); + } + + // Draw a line in the graph rect. + void DrawLine(float x1, float y1, float x2, float y2, float grayscale) + { + _lineVertices[0] = PointInRect(x1, y1); + _lineVertices[1] = PointInRect(x2, y2); + Handles.color = Color.white * grayscale; + Handles.DrawAAPolyLine(2.0f, _lineVertices); + } + + // Draw a rect in the graph rect. + void DrawRect(float x1, float y1, float x2, float y2, float fill, float line) + { + _rectVertices[0] = PointInRect(x1, y1); + _rectVertices[1] = PointInRect(x2, y1); + _rectVertices[2] = PointInRect(x2, y2); + _rectVertices[3] = PointInRect(x1, y2); + + Handles.DrawSolidRectangleWithOutline( + _rectVertices, + fill < 0 ? Color.clear : Color.white * fill, + line < 0 ? Color.clear : Color.white * line + ); + } + + #endregion + } +} diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/Bloom/Editor/BloomGraphDrawer.cs.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/Bloom/Editor/BloomGraphDrawer.cs.meta new file mode 100644 index 0000000..3bd76e8 --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/Bloom/Editor/BloomGraphDrawer.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: e2d62b6f4e4eb4c6783477b5d99abdff +timeCreated: 1465439082 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/Bloom/Resources.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/Bloom/Resources.meta new file mode 100644 index 0000000..c17ec7c --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/Bloom/Resources.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 4af3202dbe79e460e9be42bcb6509fe0 +folderAsset: yes +timeCreated: 1454052266 +licenseType: Store +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/Bloom/Resources/Bloom.cginc b/IronToad_UnityProject/Assets/Standard Assets/Effects/Bloom/Resources/Bloom.cginc new file mode 100644 index 0000000..59502f5 --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/Bloom/Resources/Bloom.cginc @@ -0,0 +1,238 @@ +#include "UnityCG.cginc" + +// Mobile: use RGBM instead of float/half RGB +#define USE_RGBM defined(SHADER_API_MOBILE) + +sampler2D _MainTex; +sampler2D _BaseTex; +float2 _MainTex_TexelSize; +float2 _BaseTex_TexelSize; +half4 _MainTex_ST; +half4 _BaseTex_ST; + +float _PrefilterOffs; +half _Threshold; +half3 _Curve; +float _SampleScale; +half _Intensity; + +// Brightness function +half Brightness(half3 c) +{ + return max(max(c.r, c.g), c.b); +} + +// 3-tap median filter +half3 Median(half3 a, half3 b, half3 c) +{ + return a + b + c - min(min(a, b), c) - max(max(a, b), c); +} + +// Clamp HDR value within a safe range +half3 SafeHDR(half3 c) { return min(c, 65000); } +half4 SafeHDR(half4 c) { return min(c, 65000); } + +// RGBM encoding/decoding +half4 EncodeHDR(float3 rgb) +{ +#if USE_RGBM + rgb *= 1.0 / 8; + float m = max(max(rgb.r, rgb.g), max(rgb.b, 1e-6)); + m = ceil(m * 255) / 255; + return half4(rgb / m, m); +#else + return half4(rgb, 0); +#endif +} + +float3 DecodeHDR(half4 rgba) +{ +#if USE_RGBM + return rgba.rgb * rgba.a * 8; +#else + return rgba.rgb; +#endif +} + +// Downsample with a 4x4 box filter +half3 DownsampleFilter(float2 uv) +{ + float4 d = _MainTex_TexelSize.xyxy * float4(-1, -1, +1, +1); + + half3 s; + s = DecodeHDR(tex2D(_MainTex, uv + d.xy)); + s += DecodeHDR(tex2D(_MainTex, uv + d.zy)); + s += DecodeHDR(tex2D(_MainTex, uv + d.xw)); + s += DecodeHDR(tex2D(_MainTex, uv + d.zw)); + + return s * (1.0 / 4); +} + +// Downsample with a 4x4 box filter + anti-flicker filter +half3 DownsampleAntiFlickerFilter(float2 uv) +{ + float4 d = _MainTex_TexelSize.xyxy * float4(-1, -1, +1, +1); + + half3 s1 = DecodeHDR(tex2D(_MainTex, uv + d.xy)); + half3 s2 = DecodeHDR(tex2D(_MainTex, uv + d.zy)); + half3 s3 = DecodeHDR(tex2D(_MainTex, uv + d.xw)); + half3 s4 = DecodeHDR(tex2D(_MainTex, uv + d.zw)); + + // Karis's luma weighted average (using brightness instead of luma) + half s1w = 1 / (Brightness(s1) + 1); + half s2w = 1 / (Brightness(s2) + 1); + half s3w = 1 / (Brightness(s3) + 1); + half s4w = 1 / (Brightness(s4) + 1); + half one_div_wsum = 1 / (s1w + s2w + s3w + s4w); + + return (s1 * s1w + s2 * s2w + s3 * s3w + s4 * s4w) * one_div_wsum; +} + +half3 UpsampleFilter(float2 uv) +{ +#if HIGH_QUALITY + // 9-tap bilinear upsampler (tent filter) + float4 d = _MainTex_TexelSize.xyxy * float4(1, 1, -1, 0) * _SampleScale; + + half3 s; + s = DecodeHDR(tex2D(_MainTex, uv - d.xy)); + s += DecodeHDR(tex2D(_MainTex, uv - d.wy)) * 2; + s += DecodeHDR(tex2D(_MainTex, uv - d.zy)); + + s += DecodeHDR(tex2D(_MainTex, uv + d.zw)) * 2; + s += DecodeHDR(tex2D(_MainTex, uv )) * 4; + s += DecodeHDR(tex2D(_MainTex, uv + d.xw)) * 2; + + s += DecodeHDR(tex2D(_MainTex, uv + d.zy)); + s += DecodeHDR(tex2D(_MainTex, uv + d.wy)) * 2; + s += DecodeHDR(tex2D(_MainTex, uv + d.xy)); + + return s * (1.0 / 16); +#else + // 4-tap bilinear upsampler + float4 d = _MainTex_TexelSize.xyxy * float4(-1, -1, +1, +1) * (_SampleScale * 0.5); + + half3 s; + s = DecodeHDR(tex2D(_MainTex, uv + d.xy)); + s += DecodeHDR(tex2D(_MainTex, uv + d.zy)); + s += DecodeHDR(tex2D(_MainTex, uv + d.xw)); + s += DecodeHDR(tex2D(_MainTex, uv + d.zw)); + + return s * (1.0 / 4); +#endif +} + +// +// Vertex shader +// + +v2f_img vert(appdata_img v) +{ + v2f_img o; +#if UNITY_VERSION >= 540 + o.pos = UnityObjectToClipPos(v.vertex); + o.uv = UnityStereoScreenSpaceUVAdjust(v.texcoord, _MainTex_ST); +#else + o.pos = mul(UNITY_MATRIX_MVP, v.vertex); + o.uv = v.texcoord; +#endif + return o; +} + +struct v2f_multitex +{ + float4 pos : SV_POSITION; + float2 uvMain : TEXCOORD0; + float2 uvBase : TEXCOORD1; +}; + +v2f_multitex vert_multitex(appdata_img v) +{ + v2f_multitex o; +#if UNITY_VERSION >= 540 + o.pos = UnityObjectToClipPos(v.vertex); + o.uvMain = UnityStereoScreenSpaceUVAdjust(v.texcoord, _MainTex_ST); + o.uvBase = UnityStereoScreenSpaceUVAdjust(v.texcoord, _BaseTex_ST); +#else + o.pos = mul(UNITY_MATRIX_MVP, v.vertex); + o.uvMain = v.texcoord; + o.uvBase = v.texcoord; +#endif +#if UNITY_UV_STARTS_AT_TOP + if (_BaseTex_TexelSize.y < 0.0) + o.uvBase.y = 1.0 - v.texcoord.y; +#endif + return o; +} + +// +// fragment shader +// + +half4 frag_prefilter(v2f_img i) : SV_Target +{ + float2 uv = i.uv + _MainTex_TexelSize.xy * _PrefilterOffs; + +#if ANTI_FLICKER + float3 d = _MainTex_TexelSize.xyx * float3(1, 1, 0); + half4 s0 = SafeHDR(tex2D(_MainTex, uv)); + half3 s1 = SafeHDR(tex2D(_MainTex, uv - d.xz).rgb); + half3 s2 = SafeHDR(tex2D(_MainTex, uv + d.xz).rgb); + half3 s3 = SafeHDR(tex2D(_MainTex, uv - d.zy).rgb); + half3 s4 = SafeHDR(tex2D(_MainTex, uv + d.zy).rgb); + half3 m = Median(Median(s0.rgb, s1, s2), s3, s4); +#else + half4 s0 = SafeHDR(tex2D(_MainTex, uv)); + half3 m = s0.rgb; +#endif + +#if UNITY_COLORSPACE_GAMMA + m = GammaToLinearSpace(m); +#endif + // Pixel brightness + half br = Brightness(m); + + // Under-threshold part: quadratic curve + half rq = clamp(br - _Curve.x, 0, _Curve.y); + rq = _Curve.z * rq * rq; + + // Combine and apply the brightness response curve. + m *= max(rq, br - _Threshold) / max(br, 1e-5); + + return EncodeHDR(m); +} + +half4 frag_downsample1(v2f_img i) : SV_Target +{ +#if ANTI_FLICKER + return EncodeHDR(DownsampleAntiFlickerFilter(i.uv)); +#else + return EncodeHDR(DownsampleFilter(i.uv)); +#endif +} + +half4 frag_downsample2(v2f_img i) : SV_Target +{ + return EncodeHDR(DownsampleFilter(i.uv)); +} + +half4 frag_upsample(v2f_multitex i) : SV_Target +{ + half3 base = DecodeHDR(tex2D(_BaseTex, i.uvBase)); + half3 blur = UpsampleFilter(i.uvMain); + return EncodeHDR(base + blur); +} + +half4 frag_upsample_final(v2f_multitex i) : SV_Target +{ + half4 base = tex2D(_BaseTex, i.uvBase); + half3 blur = UpsampleFilter(i.uvMain); +#if UNITY_COLORSPACE_GAMMA + base.rgb = GammaToLinearSpace(base.rgb); +#endif + half3 cout = base.rgb + blur * _Intensity; +#if UNITY_COLORSPACE_GAMMA + cout = LinearToGammaSpace(cout); +#endif + return half4(cout, base.a); +} diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/Bloom/Resources/Bloom.cginc.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/Bloom/Resources/Bloom.cginc.meta new file mode 100644 index 0000000..2d7c7de --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/Bloom/Resources/Bloom.cginc.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 386a80fc77a074d2ca8e6f097dd68ea3 +timeCreated: 1463538726 +licenseType: Store +ShaderImporter: + defaultTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/Bloom/Resources/Bloom.shader b/IronToad_UnityProject/Assets/Standard Assets/Effects/Bloom/Resources/Bloom.shader new file mode 100644 index 0000000..44ad6a5 --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/Bloom/Resources/Bloom.shader @@ -0,0 +1,118 @@ +Shader "Hidden/Image Effects/Cinematic/Bloom" +{ + Properties + { + _MainTex("", 2D) = "" {} + _BaseTex("", 2D) = "" {} + } + SubShader + { + // 0: Prefilter + Pass + { + ZTest Always Cull Off ZWrite Off + CGPROGRAM + #pragma multi_compile _ UNITY_COLORSPACE_GAMMA + #include "Bloom.cginc" + #pragma vertex vert + #pragma fragment frag_prefilter + #pragma target 3.0 + ENDCG + } + // 1: Prefilter with anti-flicker + Pass + { + ZTest Always Cull Off ZWrite Off + CGPROGRAM + #define ANTI_FLICKER 1 + #pragma multi_compile _ UNITY_COLORSPACE_GAMMA + #include "Bloom.cginc" + #pragma vertex vert + #pragma fragment frag_prefilter + #pragma target 3.0 + ENDCG + } + // 2: First level downsampler + Pass + { + ZTest Always Cull Off ZWrite Off + CGPROGRAM + #include "Bloom.cginc" + #pragma vertex vert + #pragma fragment frag_downsample1 + #pragma target 3.0 + ENDCG + } + // 3: First level downsampler with anti-flicker + Pass + { + ZTest Always Cull Off ZWrite Off + CGPROGRAM + #define ANTI_FLICKER 1 + #include "Bloom.cginc" + #pragma vertex vert + #pragma fragment frag_downsample1 + #pragma target 3.0 + ENDCG + } + // 4: Second level downsampler + Pass + { + ZTest Always Cull Off ZWrite Off + CGPROGRAM + #include "Bloom.cginc" + #pragma vertex vert + #pragma fragment frag_downsample2 + #pragma target 3.0 + ENDCG + } + // 5: Upsampler + Pass + { + ZTest Always Cull Off ZWrite Off + CGPROGRAM + #include "Bloom.cginc" + #pragma vertex vert_multitex + #pragma fragment frag_upsample + #pragma target 3.0 + ENDCG + } + // 6: High quality upsampler + Pass + { + ZTest Always Cull Off ZWrite Off + CGPROGRAM + #define HIGH_QUALITY 1 + #include "Bloom.cginc" + #pragma vertex vert_multitex + #pragma fragment frag_upsample + #pragma target 3.0 + ENDCG + } + // 7: Combiner + Pass + { + ZTest Always Cull Off ZWrite Off + CGPROGRAM + #pragma multi_compile _ UNITY_COLORSPACE_GAMMA + #include "Bloom.cginc" + #pragma vertex vert_multitex + #pragma fragment frag_upsample_final + #pragma target 3.0 + ENDCG + } + // 8: High quality combiner + Pass + { + ZTest Always Cull Off ZWrite Off + CGPROGRAM + #define HIGH_QUALITY 1 + #pragma multi_compile _ UNITY_COLORSPACE_GAMMA + #include "Bloom.cginc" + #pragma vertex vert_multitex + #pragma fragment frag_upsample_final + #pragma target 3.0 + ENDCG + } + } +} diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/Bloom/Resources/Bloom.shader.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/Bloom/Resources/Bloom.shader.meta new file mode 100644 index 0000000..3097437 --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/Bloom/Resources/Bloom.shader.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: e45d4f28262b04d10a075856ab5fdb5e +timeCreated: 1454052270 +licenseType: Store +ShaderImporter: + defaultTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/Common.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/Common.meta new file mode 100644 index 0000000..7511643 --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/Common.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 88d2f1c604c7f6d4bb80a72b2f0219a7 +folderAsset: yes +timeCreated: 1449044555 +licenseType: Store +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/Common/Editor.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/Common/Editor.meta new file mode 100644 index 0000000..1ecc01b --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/Common/Editor.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: e862ecde714eb154ca2d86a9a0809732 +folderAsset: yes +timeCreated: 1453372226 +licenseType: Store +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/Common/Editor/EditorGUIHelper.cs b/IronToad_UnityProject/Assets/Standard Assets/Effects/Common/Editor/EditorGUIHelper.cs new file mode 100644 index 0000000..05fb09a --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/Common/Editor/EditorGUIHelper.cs @@ -0,0 +1,62 @@ +using UnityEngine; +using UnityEditor; +using System; +using System.Linq.Expressions; +using System.Reflection; + +namespace UnityStandardAssets.CinematicEffects +{ + public static class EditorGUIHelper + { + private static Styles s_Styles; + private class Styles + { + public GUIStyle header = "ShurikenModuleTitle"; + public GUIStyle headerCheckbox = "ShurikenCheckMark"; + + internal Styles() + { + header.font = (new GUIStyle("Label")).font; + header.border = new RectOffset(15, 7, 4, 4); + header.fixedHeight = 22; + header.contentOffset = new Vector2(20f, -2f); + } + } + + static EditorGUIHelper() + { + s_Styles = new Styles(); + } + + public static bool Header(SerializedProperty group, SerializedProperty enabledField) + { + var display = group == null || group.isExpanded; + var enabled = enabledField != null && enabledField.boolValue; + var title = group == null ? "Unknown Group" : ObjectNames.NicifyVariableName(group.displayName); + + Rect rect = GUILayoutUtility.GetRect(16f, 22f, s_Styles.header); + GUI.Box(rect, title, s_Styles.header); + + Rect toggleRect = new Rect(rect.x + 4f, rect.y + 4f, 13f, 13f); + if (Event.current.type == EventType.Repaint) + s_Styles.headerCheckbox.Draw(toggleRect, false, false, enabled, false); + + Event e = Event.current; + if (e.type == EventType.MouseDown) + { + if (toggleRect.Contains(e.mousePosition) && enabledField != null) + { + enabledField.boolValue = !enabledField.boolValue; + e.Use(); + } + else if (rect.Contains(e.mousePosition) && group != null) + { + display = !display; + group.isExpanded = !group.isExpanded; + e.Use(); + } + } + return display; + } + } +} diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/Common/Editor/EditorGUIHelper.cs.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/Common/Editor/EditorGUIHelper.cs.meta new file mode 100644 index 0000000..94ced04 --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/Common/Editor/EditorGUIHelper.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 5b995f06a3ed14d449823cf7ab1c5a58 +timeCreated: 1454681943 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/Common/Editor/FieldFinder.cs b/IronToad_UnityProject/Assets/Standard Assets/Effects/Common/Editor/FieldFinder.cs new file mode 100644 index 0000000..fe77bdd --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/Common/Editor/FieldFinder.cs @@ -0,0 +1,25 @@ +using System; +using System.Linq.Expressions; +using System.Reflection; + +namespace UnityStandardAssets.CinematicEffects +{ + public static class FieldFinder + { + public static FieldInfo GetField(Expression> selector) + { + Expression body = selector; + if (body is LambdaExpression) + { + body = ((LambdaExpression)body).Body; + } + switch (body.NodeType) + { + case ExpressionType.MemberAccess: + return (FieldInfo)((MemberExpression)body).Member; + default: + throw new InvalidOperationException(); + } + } + } +} diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/Common/Editor/FieldFinder.cs.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/Common/Editor/FieldFinder.cs.meta new file mode 100644 index 0000000..c4f8182 --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/Common/Editor/FieldFinder.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 39e54cb37a3a81a40b248f1cc25c4619 +timeCreated: 1454073160 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/Common/Editor/MinDrawer.cs b/IronToad_UnityProject/Assets/Standard Assets/Effects/Common/Editor/MinDrawer.cs new file mode 100644 index 0000000..73ca7b2 --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/Common/Editor/MinDrawer.cs @@ -0,0 +1,29 @@ +using UnityEditor; +using UnityEngine; + +namespace UnityStandardAssets.CinematicEffects +{ + [CustomPropertyDrawer(typeof(MinAttribute))] + internal sealed class MinDrawer : PropertyDrawer + { + public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) + { + MinAttribute attribute = (MinAttribute) base.attribute; + + if (property.propertyType == SerializedPropertyType.Integer) + { + int v = EditorGUI.IntField(position, label, property.intValue); + property.intValue = (int)Mathf.Max(v, attribute.min); + } + else if (property.propertyType == SerializedPropertyType.Float) + { + float v = EditorGUI.FloatField(position, label, property.floatValue); + property.floatValue = Mathf.Max(v, attribute.min); + } + else + { + EditorGUI.LabelField(position, label.text, "Use Min with float or int."); + } + } + } +} diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/Common/Editor/MinDrawer.cs.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/Common/Editor/MinDrawer.cs.meta new file mode 100644 index 0000000..c053e4d --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/Common/Editor/MinDrawer.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 9c615a85f13c6764fa4496d1d7f75f52 +timeCreated: 1453220014 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/Common/ImageEffectHelper.cs b/IronToad_UnityProject/Assets/Standard Assets/Effects/Common/ImageEffectHelper.cs new file mode 100644 index 0000000..d3761b6 --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/Common/ImageEffectHelper.cs @@ -0,0 +1,63 @@ +using UnityEngine; +#if UNITY_EDITOR +using UnityEditor; +#endif + +namespace UnityStandardAssets.CinematicEffects +{ + public static class ImageEffectHelper + { + public static bool IsSupported(Shader s, bool needDepth, bool needHdr, MonoBehaviour effect) + { +#if UNITY_EDITOR + // Don't check for shader compatibility while it's building as it would disable most effects + // on build farms without good-enough gaming hardware. + if (!BuildPipeline.isBuildingPlayer) + { +#endif + if (s == null || !s.isSupported) + { + Debug.LogWarningFormat("Missing shader for image effect {0}", effect); + return false; + } + + if (!SystemInfo.supportsImageEffects || !SystemInfo.supportsRenderTextures) + { + Debug.LogWarningFormat("Image effects aren't supported on this device ({0})", effect); + return false; + } + + if (needDepth && !SystemInfo.SupportsRenderTextureFormat(RenderTextureFormat.Depth)) + { + Debug.LogWarningFormat("Depth textures aren't supported on this device ({0})", effect); + return false; + } + + if (needHdr && !SystemInfo.SupportsRenderTextureFormat(RenderTextureFormat.ARGBHalf)) + { + Debug.LogWarningFormat("Floating point textures aren't supported on this device ({0})", effect); + return false; + } +#if UNITY_EDITOR + } +#endif + + return true; + } + + public static Material CheckShaderAndCreateMaterial(Shader s) + { + if (s == null || !s.isSupported) + return null; + + var material = new Material(s); + material.hideFlags = HideFlags.DontSave; + return material; + } + + public static bool supportsDX11 + { + get { return SystemInfo.graphicsShaderLevel >= 50 && SystemInfo.supportsComputeShaders; } + } + } +} diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/Common/ImageEffectHelper.cs.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/Common/ImageEffectHelper.cs.meta new file mode 100644 index 0000000..2e5b46d --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/Common/ImageEffectHelper.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: ab6a3f50deeee984c88794eeeb901226 +timeCreated: 1448544124 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/Common/MinAttribute.cs b/IronToad_UnityProject/Assets/Standard Assets/Effects/Common/MinAttribute.cs new file mode 100644 index 0000000..84e7c1a --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/Common/MinAttribute.cs @@ -0,0 +1,14 @@ +namespace UnityStandardAssets.CinematicEffects +{ + using UnityEngine; + + public sealed class MinAttribute : PropertyAttribute + { + public readonly float min; + + public MinAttribute(float min) + { + this.min = min; + } + } +} diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/Common/MinAttribute.cs.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/Common/MinAttribute.cs.meta new file mode 100644 index 0000000..0b42bb8 --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/Common/MinAttribute.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: b07292ae638766047a6751da7552e566 +timeCreated: 1453220005 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/Common/RenderTextureUtility.cs b/IronToad_UnityProject/Assets/Standard Assets/Effects/Common/RenderTextureUtility.cs new file mode 100644 index 0000000..ae71657 --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/Common/RenderTextureUtility.cs @@ -0,0 +1,44 @@ +using System.Collections.Generic; +using UnityEngine; + +namespace UnityStandardAssets.CinematicEffects +{ + public class RenderTextureUtility + { + //Temporary render texture handling + private List m_TemporaryRTs = new List(); + + public RenderTexture GetTemporaryRenderTexture(int width, int height, int depthBuffer = 0, RenderTextureFormat format = RenderTextureFormat.ARGBHalf, FilterMode filterMode = FilterMode.Bilinear) + { + var rt = RenderTexture.GetTemporary(width, height, depthBuffer, format); + rt.filterMode = filterMode; + rt.wrapMode = TextureWrapMode.Clamp; + rt.name = "RenderTextureUtilityTempTexture"; + m_TemporaryRTs.Add(rt); + return rt; + } + + public void ReleaseTemporaryRenderTexture(RenderTexture rt) + { + if (rt == null) + return; + + if (!m_TemporaryRTs.Contains(rt)) + { + Debug.LogErrorFormat("Attempting to remove texture that was not allocated: {0}", rt); + return; + } + + m_TemporaryRTs.Remove(rt); + RenderTexture.ReleaseTemporary(rt); + } + + public void ReleaseAllTemporaryRenderTextures() + { + for (int i = 0; i < m_TemporaryRTs.Count; ++i) + RenderTexture.ReleaseTemporary(m_TemporaryRTs[i]); + + m_TemporaryRTs.Clear(); + } + } +} diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/Common/RenderTextureUtility.cs.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/Common/RenderTextureUtility.cs.meta new file mode 100644 index 0000000..6de4df1 --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/Common/RenderTextureUtility.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 054e694bae00c374a97c2bc495fca66b +timeCreated: 1449148391 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/DepthOfField.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/DepthOfField.meta new file mode 100644 index 0000000..85f341c --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/DepthOfField.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 34369cdf66de04c65a8cef766bb1797b +folderAsset: yes +timeCreated: 1429220270 +licenseType: Store +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/DepthOfField/DepthOfField.cs b/IronToad_UnityProject/Assets/Standard Assets/Effects/DepthOfField/DepthOfField.cs new file mode 100644 index 0000000..0f9da65 --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/DepthOfField/DepthOfField.cs @@ -0,0 +1,846 @@ +using UnityEngine; +using System; + +namespace UnityStandardAssets.CinematicEffects +{ + //Improvement ideas: + // Use rgba8 buffer in ldr / in some pass in hdr (in correlation to previous point and remapping coc from -1/0/1 to 0/0.5/1) + // Use temporal stabilisation + // Add a mode to do bokeh texture in quarter res as well + // Support different near and far blur for the bokeh texture + // Try distance field for the bokeh texture + // Try to separate the output of the blur pass to two rendertarget near+far, see the gain in quality vs loss in performance + // Try swirl effect on the samples of the circle blur + + //References : + // This DOF implementation use ideas from public sources, a big thank to them : + // http://www.iryoku.com/next-generation-post-processing-in-call-of-duty-advanced-warfare + // http://www.crytek.com/download/Sousa_Graphics_Gems_CryENGINE3.pdf + // http://graphics.cs.williams.edu/papers/MedianShaderX6/ + // http://http.developer.nvidia.com/GPUGems/gpugems_ch24.html + // http://vec3.ca/bicubic-filtering-in-fewer-taps/ + + [ExecuteInEditMode] + [AddComponentMenu("Image Effects/Cinematic/Depth Of Field")] + [RequireComponent(typeof(Camera))] + public class DepthOfField : MonoBehaviour + { + private const float kMaxBlur = 40.0f; + + #region Render passes + private enum Passes + { + BlurAlphaWeighted, + BoxBlur, + DilateFgCocFromColor, + DilateFgCoc, + CaptureCocExplicit, + VisualizeCocExplicit, + CocPrefilter, + CircleBlur, + CircleBlurWithDilatedFg, + CircleBlurLowQuality, + CircleBlowLowQualityWithDilatedFg, + MergeExplicit, + ShapeLowQuality, + ShapeLowQualityDilateFg, + ShapeLowQualityMerge, + ShapeLowQualityMergeDilateFg, + ShapeMediumQuality, + ShapeMediumQualityDilateFg, + ShapeMediumQualityMerge, + ShapeMediumQualityMergeDilateFg, + ShapeHighQuality, + ShapeHighQualityDilateFg, + ShapeHighQualityMerge, + ShapeHighQualityMergeDilateFg + } + + private enum MedianPasses + { + Median3, + Median3X3 + } + + private enum BokehTexturesPasses + { + Apply, + Collect + } + #endregion + + public enum TweakMode + { + Range, + Explicit + } + + public enum ApertureShape + { + Circular, + Hexagonal, + Octogonal + } + + public enum QualityPreset + { + Low, + Medium, + High + } + + public enum FilterQuality + { + None, + Normal, + High + } + + #region Settings + [Serializable] + public struct GlobalSettings + { + [Tooltip("Allows to view where the blur will be applied. Yellow for near blur, blue for far blur.")] + public bool visualizeFocus; + + [Tooltip("Setup mode. Use \"Advanced\" if you need more control on blur settings and/or want to use a bokeh texture. \"Explicit\" is the same as \"Advanced\" but makes use of \"Near Plane\" and \"Far Plane\" values instead of \"F-Stop\".")] + public TweakMode tweakMode; + + [Tooltip("Quality presets. Use \"Custom\" for more advanced settings.")] + public QualityPreset filteringQuality; + + [Tooltip("\"Circular\" is the fastest, followed by \"Hexagonal\" and \"Octogonal\".")] + public ApertureShape apertureShape; + + [Range(0f, 179f), Tooltip("Rotates the aperture when working with \"Hexagonal\" and \"Ortogonal\".")] + public float apertureOrientation; + + public static GlobalSettings defaultSettings + { + get + { + return new GlobalSettings + { + visualizeFocus = false, + tweakMode = TweakMode.Range, + filteringQuality = QualityPreset.High, + apertureShape = ApertureShape.Circular, + apertureOrientation = 0f + }; + } + } + } + + [Serializable] + public struct QualitySettings + { + [Tooltip("Enable this to get smooth bokeh.")] + public bool prefilterBlur; + + [Tooltip("Applies a median filter for even smoother bokeh.")] + public FilterQuality medianFilter; + + [Tooltip("Dilates near blur over in focus area.")] + public bool dilateNearBlur; + + public static QualitySettings[] presetQualitySettings = + { + // Low + new QualitySettings + { + prefilterBlur = false, + medianFilter = FilterQuality.None, + dilateNearBlur = false + }, + + // Medium + new QualitySettings + { + prefilterBlur = true, + medianFilter = FilterQuality.Normal, + dilateNearBlur = false + }, + + // High + new QualitySettings + { + prefilterBlur = true, + medianFilter = FilterQuality.High, + dilateNearBlur = true + } + }; + } + + [Serializable] + public struct FocusSettings + { + [Tooltip("Auto-focus on a selected transform.")] + public Transform transform; + + [Min(0f), Tooltip("Focus distance (in world units).")] + public float focusPlane; + + [Min(0.1f), Tooltip("Focus range (in world units). The focus plane is located in the center of the range.")] + public float range; + + [Min(0f), Tooltip("Near focus distance (in world units).")] + public float nearPlane; + + [Min(0f), Tooltip("Near blur falloff (in world units).")] + public float nearFalloff; + + [Min(0f), Tooltip("Far focus distance (in world units).")] + public float farPlane; + + [Min(0f), Tooltip("Far blur falloff (in world units).")] + public float farFalloff; + + [Range(0f, kMaxBlur), Tooltip("Maximum blur radius for the near plane.")] + public float nearBlurRadius; + + [Range(0f, kMaxBlur), Tooltip("Maximum blur radius for the far plane.")] + public float farBlurRadius; + + public static FocusSettings defaultSettings + { + get + { + return new FocusSettings + { + transform = null, + focusPlane = 20f, + range = 35f, + nearPlane = 2.5f, + nearFalloff = 15f, + farPlane = 37.5f, + farFalloff = 50f, + nearBlurRadius = 15f, + farBlurRadius = 20f + }; + } + } + } + + [Serializable] + public struct BokehTextureSettings + { + [Tooltip("Adding a texture to this field will enable the use of \"Bokeh Textures\". Use with care. This feature is only available on Shader Model 5 compatible-hardware and performance scale with the amount of bokeh.")] + public Texture2D texture; + + [Range(0.01f, 10f), Tooltip("Maximum size of bokeh textures on screen.")] + public float scale; + + [Range(0.01f, 100f), Tooltip("Bokeh brightness.")] + public float intensity; + + [Range(0.01f, 5f), Tooltip("Controls the amount of bokeh textures. Lower values mean more bokeh splats.")] + public float threshold; + + [Range(0.01f, 1f), Tooltip("Controls the spawn conditions. Lower values mean more visible bokeh.")] + public float spawnHeuristic; + + public static BokehTextureSettings defaultSettings + { + get + { + return new BokehTextureSettings + { + texture = null, + scale = 1f, + intensity = 50f, + threshold = 2f, + spawnHeuristic = 0.15f + }; + } + } + } + #endregion + + public GlobalSettings settings = GlobalSettings.defaultSettings; + public FocusSettings focus = FocusSettings.defaultSettings; + public BokehTextureSettings bokehTexture = BokehTextureSettings.defaultSettings; + + [SerializeField] + private Shader m_FilmicDepthOfFieldShader; + + public Shader filmicDepthOfFieldShader + { + get + { + if (m_FilmicDepthOfFieldShader == null) + m_FilmicDepthOfFieldShader = Shader.Find("Hidden/DepthOfField/DepthOfField"); + + return m_FilmicDepthOfFieldShader; + } + } + + [SerializeField] + private Shader m_MedianFilterShader; + + public Shader medianFilterShader + { + get + { + if (m_MedianFilterShader == null) + m_MedianFilterShader = Shader.Find("Hidden/DepthOfField/MedianFilter"); + + return m_MedianFilterShader; + } + } + + [SerializeField] + private Shader m_TextureBokehShader; + + public Shader textureBokehShader + { + get + { + if (m_TextureBokehShader == null) + m_TextureBokehShader = Shader.Find("Hidden/DepthOfField/BokehSplatting"); + + return m_TextureBokehShader; + } + } + + private RenderTextureUtility m_RTU = new RenderTextureUtility(); + + private Material m_FilmicDepthOfFieldMaterial; + + public Material filmicDepthOfFieldMaterial + { + get + { + if (m_FilmicDepthOfFieldMaterial == null) + m_FilmicDepthOfFieldMaterial = ImageEffectHelper.CheckShaderAndCreateMaterial(filmicDepthOfFieldShader); + + return m_FilmicDepthOfFieldMaterial; + } + } + + private Material m_MedianFilterMaterial; + + public Material medianFilterMaterial + { + get + { + if (m_MedianFilterMaterial == null) + m_MedianFilterMaterial = ImageEffectHelper.CheckShaderAndCreateMaterial(medianFilterShader); + + return m_MedianFilterMaterial; + } + } + + private Material m_TextureBokehMaterial; + + public Material textureBokehMaterial + { + get + { + if (m_TextureBokehMaterial == null) + m_TextureBokehMaterial = ImageEffectHelper.CheckShaderAndCreateMaterial(textureBokehShader); + + return m_TextureBokehMaterial; + } + } + + private ComputeBuffer m_ComputeBufferDrawArgs; + + public ComputeBuffer computeBufferDrawArgs + { + get + { + if (m_ComputeBufferDrawArgs == null) + { +#if UNITY_5_4_OR_NEWER + m_ComputeBufferDrawArgs = new ComputeBuffer(1, 16, ComputeBufferType.IndirectArguments); +#else + m_ComputeBufferDrawArgs = new ComputeBuffer(1, 16, ComputeBufferType.DrawIndirect); +#endif + m_ComputeBufferDrawArgs.SetData(new[] {0, 1, 0, 0}); + } + + return m_ComputeBufferDrawArgs; + } + } + + private ComputeBuffer m_ComputeBufferPoints; + + public ComputeBuffer computeBufferPoints + { + get + { + if (m_ComputeBufferPoints == null) + m_ComputeBufferPoints = new ComputeBuffer(90000, 12 + 16, ComputeBufferType.Append); + + return m_ComputeBufferPoints; + } + } + + private QualitySettings m_CurrentQualitySettings; + private float m_LastApertureOrientation; + private Vector4 m_OctogonalBokehDirection1; + private Vector4 m_OctogonalBokehDirection2; + private Vector4 m_OctogonalBokehDirection3; + private Vector4 m_OctogonalBokehDirection4; + private Vector4 m_HexagonalBokehDirection1; + private Vector4 m_HexagonalBokehDirection2; + private Vector4 m_HexagonalBokehDirection3; + + private void OnEnable() + { + if (!ImageEffectHelper.IsSupported(filmicDepthOfFieldShader, true, true, this) || !ImageEffectHelper.IsSupported(medianFilterShader, true, true, this)) + { + enabled = false; + return; + } + + if (ImageEffectHelper.supportsDX11 && !ImageEffectHelper.IsSupported(textureBokehShader, true, true, this)) + { + enabled = false; + return; + } + + ComputeBlurDirections(true); + GetComponent().depthTextureMode |= DepthTextureMode.Depth; + } + + private void OnDisable() + { + ReleaseComputeResources(); + + if (m_FilmicDepthOfFieldMaterial != null) + DestroyImmediate(m_FilmicDepthOfFieldMaterial); + + if (m_TextureBokehMaterial != null) + DestroyImmediate(m_TextureBokehMaterial); + + if (m_MedianFilterMaterial != null) + DestroyImmediate(m_MedianFilterMaterial); + + m_FilmicDepthOfFieldMaterial = null; + m_TextureBokehMaterial = null; + m_MedianFilterMaterial = null; + + m_RTU.ReleaseAllTemporaryRenderTextures(); + } + + //-------------------------------------------------------------------// + // Main entry point // + //-------------------------------------------------------------------// + private void OnRenderImage(RenderTexture source, RenderTexture destination) + { + if (medianFilterMaterial == null || filmicDepthOfFieldMaterial == null) + { + Graphics.Blit(source, destination); + return; + } + + if (settings.visualizeFocus) + { + Vector4 blurrinessParam; + Vector4 blurrinessCoe; + ComputeCocParameters(out blurrinessParam, out blurrinessCoe); + filmicDepthOfFieldMaterial.SetVector("_BlurParams", blurrinessParam); + filmicDepthOfFieldMaterial.SetVector("_BlurCoe", blurrinessCoe); + Graphics.Blit(null, destination, filmicDepthOfFieldMaterial, (int)Passes.VisualizeCocExplicit); + } + else + { + DoDepthOfField(source, destination); + } + + m_RTU.ReleaseAllTemporaryRenderTextures(); + } + + private void DoDepthOfField(RenderTexture source, RenderTexture destination) + { + m_CurrentQualitySettings = QualitySettings.presetQualitySettings[(int)settings.filteringQuality]; + + float radiusAdjustement = source.height / 720f; + + float textureBokehScale = radiusAdjustement; + float textureBokehMaxRadius = Mathf.Max(focus.nearBlurRadius, focus.farBlurRadius) * textureBokehScale * 0.75f; + + float nearBlurRadius = focus.nearBlurRadius * radiusAdjustement; + float farBlurRadius = focus.farBlurRadius * radiusAdjustement; + float maxBlurRadius = Mathf.Max(nearBlurRadius, farBlurRadius); + switch (settings.apertureShape) + { + case ApertureShape.Hexagonal: + maxBlurRadius *= 1.2f; + break; + case ApertureShape.Octogonal: + maxBlurRadius *= 1.15f; + break; + } + + if (maxBlurRadius < 0.5f) + { + Graphics.Blit(source, destination); + return; + } + + // Quarter resolution + int rtW = source.width / 2; + int rtH = source.height / 2; + var blurrinessCoe = new Vector4(nearBlurRadius * 0.5f, farBlurRadius * 0.5f, 0f, 0f); + var colorAndCoc = m_RTU.GetTemporaryRenderTexture(rtW, rtH); + var colorAndCoc2 = m_RTU.GetTemporaryRenderTexture(rtW, rtH); + + // Downsample to Color + COC buffer + Vector4 cocParam; + Vector4 cocCoe; + ComputeCocParameters(out cocParam, out cocCoe); + filmicDepthOfFieldMaterial.SetVector("_BlurParams", cocParam); + filmicDepthOfFieldMaterial.SetVector("_BlurCoe", cocCoe); + Graphics.Blit(source, colorAndCoc2, filmicDepthOfFieldMaterial, (int)Passes.CaptureCocExplicit); + var src = colorAndCoc2; + var dst = colorAndCoc; + + // Collect texture bokeh candidates and replace with a darker pixel + if (shouldPerformBokeh) + { + // Blur a bit so we can do a frequency check + var blurred = m_RTU.GetTemporaryRenderTexture(rtW, rtH); + Graphics.Blit(src, blurred, filmicDepthOfFieldMaterial, (int)Passes.BoxBlur); + filmicDepthOfFieldMaterial.SetVector("_Offsets", new Vector4(0f, 1.5f, 0f, 1.5f)); + Graphics.Blit(blurred, dst, filmicDepthOfFieldMaterial, (int)Passes.BlurAlphaWeighted); + filmicDepthOfFieldMaterial.SetVector("_Offsets", new Vector4(1.5f, 0f, 0f, 1.5f)); + Graphics.Blit(dst, blurred, filmicDepthOfFieldMaterial, (int)Passes.BlurAlphaWeighted); + + // Collect texture bokeh candidates and replace with a darker pixel + textureBokehMaterial.SetTexture("_BlurredColor", blurred); + textureBokehMaterial.SetFloat("_SpawnHeuristic", bokehTexture.spawnHeuristic); + textureBokehMaterial.SetVector("_BokehParams", new Vector4(bokehTexture.scale * textureBokehScale, bokehTexture.intensity, bokehTexture.threshold, textureBokehMaxRadius)); + Graphics.SetRandomWriteTarget(1, computeBufferPoints); + Graphics.Blit(src, dst, textureBokehMaterial, (int)BokehTexturesPasses.Collect); + Graphics.ClearRandomWriteTargets(); + SwapRenderTexture(ref src, ref dst); + m_RTU.ReleaseTemporaryRenderTexture(blurred); + } + + filmicDepthOfFieldMaterial.SetVector("_BlurParams", cocParam); + filmicDepthOfFieldMaterial.SetVector("_BlurCoe", blurrinessCoe); + + // Dilate near blur factor + RenderTexture blurredFgCoc = null; + if (m_CurrentQualitySettings.dilateNearBlur) + { + var blurredFgCoc2 = m_RTU.GetTemporaryRenderTexture(rtW, rtH, 0, RenderTextureFormat.RGHalf); + blurredFgCoc = m_RTU.GetTemporaryRenderTexture(rtW, rtH, 0, RenderTextureFormat.RGHalf); + filmicDepthOfFieldMaterial.SetVector("_Offsets", new Vector4(0f, nearBlurRadius * 0.75f, 0f, 0f)); + Graphics.Blit(src, blurredFgCoc2, filmicDepthOfFieldMaterial, (int)Passes.DilateFgCocFromColor); + filmicDepthOfFieldMaterial.SetVector("_Offsets", new Vector4(nearBlurRadius * 0.75f, 0f, 0f, 0f)); + Graphics.Blit(blurredFgCoc2, blurredFgCoc, filmicDepthOfFieldMaterial, (int)Passes.DilateFgCoc); + m_RTU.ReleaseTemporaryRenderTexture(blurredFgCoc2); + blurredFgCoc.filterMode = FilterMode.Point; + } + + // Blur downsampled color to fill the gap between samples + if (m_CurrentQualitySettings.prefilterBlur) + { + Graphics.Blit(src, dst, filmicDepthOfFieldMaterial, (int)Passes.CocPrefilter); + SwapRenderTexture(ref src, ref dst); + } + + // Apply blur : Circle / Hexagonal or Octagonal (blur will create bokeh if bright pixel where not removed by "m_UseBokehTexture") + switch (settings.apertureShape) + { + case ApertureShape.Circular: + DoCircularBlur(blurredFgCoc, ref src, ref dst, maxBlurRadius); + break; + case ApertureShape.Hexagonal: + DoHexagonalBlur(blurredFgCoc, ref src, ref dst, maxBlurRadius); + break; + case ApertureShape.Octogonal: + DoOctogonalBlur(blurredFgCoc, ref src, ref dst, maxBlurRadius); + break; + } + + // Smooth result + switch (m_CurrentQualitySettings.medianFilter) + { + case FilterQuality.Normal: + { + medianFilterMaterial.SetVector("_Offsets", new Vector4(1f, 0f, 0f, 0f)); + Graphics.Blit(src, dst, medianFilterMaterial, (int)MedianPasses.Median3); + SwapRenderTexture(ref src, ref dst); + medianFilterMaterial.SetVector("_Offsets", new Vector4(0f, 1f, 0f, 0f)); + Graphics.Blit(src, dst, medianFilterMaterial, (int)MedianPasses.Median3); + SwapRenderTexture(ref src, ref dst); + break; + } + case FilterQuality.High: + { + Graphics.Blit(src, dst, medianFilterMaterial, (int)MedianPasses.Median3X3); + SwapRenderTexture(ref src, ref dst); + break; + } + } + + // Merge to full resolution (with boost) + upsampling (linear or bicubic) + filmicDepthOfFieldMaterial.SetVector("_BlurCoe", blurrinessCoe); + filmicDepthOfFieldMaterial.SetVector("_Convolved_TexelSize", new Vector4(src.width, src.height, 1f / src.width, 1f / src.height)); + filmicDepthOfFieldMaterial.SetTexture("_SecondTex", src); + int mergePass = (int)Passes.MergeExplicit; + + // Apply texture bokeh + if (shouldPerformBokeh) + { + var tmp = m_RTU.GetTemporaryRenderTexture(source.height, source.width, 0, source.format); + Graphics.Blit(source, tmp, filmicDepthOfFieldMaterial, mergePass); + + Graphics.SetRenderTarget(tmp); + ComputeBuffer.CopyCount(computeBufferPoints, computeBufferDrawArgs, 0); + textureBokehMaterial.SetBuffer("pointBuffer", computeBufferPoints); + textureBokehMaterial.SetTexture("_MainTex", bokehTexture.texture); + textureBokehMaterial.SetVector("_Screen", new Vector3(1f / (1f * source.width), 1f / (1f * source.height), textureBokehMaxRadius)); + textureBokehMaterial.SetPass((int)BokehTexturesPasses.Apply); + Graphics.DrawProceduralIndirect(MeshTopology.Points, computeBufferDrawArgs, 0); + Graphics.Blit(tmp, destination); // Hackaround for DX11 flipfun (OPTIMIZEME) + } + else + { + Graphics.Blit(source, destination, filmicDepthOfFieldMaterial, mergePass); + } + } + + //-------------------------------------------------------------------// + // Blurs // + //-------------------------------------------------------------------// + private void DoHexagonalBlur(RenderTexture blurredFgCoc, ref RenderTexture src, ref RenderTexture dst, float maxRadius) + { + ComputeBlurDirections(false); + + int blurPass; + int blurPassMerge; + GetDirectionalBlurPassesFromRadius(blurredFgCoc, maxRadius, out blurPass, out blurPassMerge); + filmicDepthOfFieldMaterial.SetTexture("_SecondTex", blurredFgCoc); + var tmp = m_RTU.GetTemporaryRenderTexture(src.width, src.height, 0, src.format); + + filmicDepthOfFieldMaterial.SetVector("_Offsets", m_HexagonalBokehDirection1); + Graphics.Blit(src, tmp, filmicDepthOfFieldMaterial, blurPass); + + filmicDepthOfFieldMaterial.SetVector("_Offsets", m_HexagonalBokehDirection2); + Graphics.Blit(tmp, src, filmicDepthOfFieldMaterial, blurPass); + + filmicDepthOfFieldMaterial.SetVector("_Offsets", m_HexagonalBokehDirection3); + filmicDepthOfFieldMaterial.SetTexture("_ThirdTex", src); + Graphics.Blit(tmp, dst, filmicDepthOfFieldMaterial, blurPassMerge); + m_RTU.ReleaseTemporaryRenderTexture(tmp); + SwapRenderTexture(ref src, ref dst); + } + + private void DoOctogonalBlur(RenderTexture blurredFgCoc, ref RenderTexture src, ref RenderTexture dst, float maxRadius) + { + ComputeBlurDirections(false); + + int blurPass; + int blurPassMerge; + GetDirectionalBlurPassesFromRadius(blurredFgCoc, maxRadius, out blurPass, out blurPassMerge); + filmicDepthOfFieldMaterial.SetTexture("_SecondTex", blurredFgCoc); + var tmp = m_RTU.GetTemporaryRenderTexture(src.width, src.height, 0, src.format); + + filmicDepthOfFieldMaterial.SetVector("_Offsets", m_OctogonalBokehDirection1); + Graphics.Blit(src, tmp, filmicDepthOfFieldMaterial, blurPass); + + filmicDepthOfFieldMaterial.SetVector("_Offsets", m_OctogonalBokehDirection2); + Graphics.Blit(tmp, dst, filmicDepthOfFieldMaterial, blurPass); + + filmicDepthOfFieldMaterial.SetVector("_Offsets", m_OctogonalBokehDirection3); + Graphics.Blit(src, tmp, filmicDepthOfFieldMaterial, blurPass); + + filmicDepthOfFieldMaterial.SetVector("_Offsets", m_OctogonalBokehDirection4); + filmicDepthOfFieldMaterial.SetTexture("_ThirdTex", dst); + Graphics.Blit(tmp, src, filmicDepthOfFieldMaterial, blurPassMerge); + m_RTU.ReleaseTemporaryRenderTexture(tmp); + } + + private void DoCircularBlur(RenderTexture blurredFgCoc, ref RenderTexture src, ref RenderTexture dst, float maxRadius) + { + int bokehPass; + + if (blurredFgCoc != null) + { + filmicDepthOfFieldMaterial.SetTexture("_SecondTex", blurredFgCoc); + bokehPass = (maxRadius > 10f) ? (int)Passes.CircleBlurWithDilatedFg : (int)Passes.CircleBlowLowQualityWithDilatedFg; + } + else + { + bokehPass = (maxRadius > 10f) ? (int)Passes.CircleBlur : (int)Passes.CircleBlurLowQuality; + } + + Graphics.Blit(src, dst, filmicDepthOfFieldMaterial, bokehPass); + SwapRenderTexture(ref src, ref dst); + } + + //-------------------------------------------------------------------// + // Helpers // + //-------------------------------------------------------------------// + private void ComputeCocParameters(out Vector4 blurParams, out Vector4 blurCoe) + { + var sceneCamera = GetComponent(); + + float focusDistance; + float nearFalloff = focus.nearFalloff * 2f; + float farFalloff = focus.farFalloff * 2f; + float nearPlane = focus.nearPlane; + float farPlane = focus.farPlane; + + if (settings.tweakMode == TweakMode.Range) + { + if (focus.transform != null) + focusDistance = sceneCamera.WorldToViewportPoint(focus.transform.position).z; + else + focusDistance = focus.focusPlane; + + float s = focus.range * 0.5f; + nearPlane = focusDistance - s; + farPlane = focusDistance + s; + } + + nearPlane -= (nearFalloff * 0.5f); + farPlane += (farFalloff * 0.5f); + focusDistance = (nearPlane + farPlane) * 0.5f; + + float focusDistance01 = focusDistance / sceneCamera.farClipPlane; + float nearDistance01 = nearPlane / sceneCamera.farClipPlane; + float farDistance01 = farPlane / sceneCamera.farClipPlane; + + var dof = farPlane - nearPlane; + var dof01 = farDistance01 - nearDistance01; + var nearFalloff01 = nearFalloff / dof; + var farFalloff01 = farFalloff / dof; + float nearFocusRange01 = (1f - nearFalloff01) * (dof01 * 0.5f); + float farFocusRange01 = (1f - farFalloff01) * (dof01 * 0.5f); + + if (focusDistance01 <= nearDistance01) + focusDistance01 = nearDistance01 + 1e-6f; + if (focusDistance01 >= farDistance01) + focusDistance01 = farDistance01 - 1e-6f; + + if ((focusDistance01 - nearFocusRange01) <= nearDistance01) + nearFocusRange01 = focusDistance01 - nearDistance01 - 1e-6f; + if ((focusDistance01 + farFocusRange01) >= farDistance01) + farFocusRange01 = farDistance01 - focusDistance01 - 1e-6f; + + float a1 = 1f / (nearDistance01 - focusDistance01 + nearFocusRange01); + float a2 = 1f / (farDistance01 - focusDistance01 - farFocusRange01); + float b1 = 1f - a1 * nearDistance01; + float b2 = 1f - a2 * farDistance01; + const float c1 = -1f; + const float c2 = 1f; + blurParams = new Vector4(c1 * a1, c1 * b1, c2 * a2, c2 * b2); + blurCoe = new Vector4(0f, 0f, (b2 - b1) / (a1 - a2), 0f); + + // Save values so we can switch from one tweak mode to the other on the fly + focus.nearPlane = nearPlane + (nearFalloff * 0.5f); + focus.farPlane = farPlane - (farFalloff * 0.5f); + focus.focusPlane = (focus.nearPlane + focus.farPlane) * 0.5f; + focus.range = focus.farPlane - focus.nearPlane; + } + + private void ReleaseComputeResources() + { + if (m_ComputeBufferDrawArgs != null) + m_ComputeBufferDrawArgs.Release(); + + if (m_ComputeBufferPoints != null) + m_ComputeBufferPoints.Release(); + + m_ComputeBufferDrawArgs = null; + m_ComputeBufferPoints = null; + } + + private void ComputeBlurDirections(bool force) + { + if (!force && Math.Abs(m_LastApertureOrientation - settings.apertureOrientation) < float.Epsilon) + return; + + m_LastApertureOrientation = settings.apertureOrientation; + + float rotationRadian = settings.apertureOrientation * Mathf.Deg2Rad; + float cosinus = Mathf.Cos(rotationRadian); + float sinus = Mathf.Sin(rotationRadian); + + m_OctogonalBokehDirection1 = new Vector4(0.5f, 0f, 0f, 0f); + m_OctogonalBokehDirection2 = new Vector4(0f, 0.5f, 1f, 0f); + m_OctogonalBokehDirection3 = new Vector4(-0.353553f, 0.353553f, 1f, 0f); + m_OctogonalBokehDirection4 = new Vector4(0.353553f, 0.353553f, 1f, 0f); + + m_HexagonalBokehDirection1 = new Vector4(0.5f, 0f, 0f, 0f); + m_HexagonalBokehDirection2 = new Vector4(0.25f, 0.433013f, 1f, 0f); + m_HexagonalBokehDirection3 = new Vector4(0.25f, -0.433013f, 1f, 0f); + + if (rotationRadian > float.Epsilon) + { + Rotate2D(ref m_OctogonalBokehDirection1, cosinus, sinus); + Rotate2D(ref m_OctogonalBokehDirection2, cosinus, sinus); + Rotate2D(ref m_OctogonalBokehDirection3, cosinus, sinus); + Rotate2D(ref m_OctogonalBokehDirection4, cosinus, sinus); + Rotate2D(ref m_HexagonalBokehDirection1, cosinus, sinus); + Rotate2D(ref m_HexagonalBokehDirection2, cosinus, sinus); + Rotate2D(ref m_HexagonalBokehDirection3, cosinus, sinus); + } + } + + private bool shouldPerformBokeh + { + get { return ImageEffectHelper.supportsDX11 && bokehTexture.texture != null && textureBokehMaterial; } + } + + private static void Rotate2D(ref Vector4 direction, float cosinus, float sinus) + { + var source = direction; + direction.x = source.x * cosinus - source.y * sinus; + direction.y = source.x * sinus + source.y * cosinus; + } + + private static void SwapRenderTexture(ref RenderTexture src, ref RenderTexture dst) + { + RenderTexture tmp = dst; + dst = src; + src = tmp; + } + + private static void GetDirectionalBlurPassesFromRadius(RenderTexture blurredFgCoc, float maxRadius, out int blurPass, out int blurAndMergePass) + { + if (blurredFgCoc == null) + { + if (maxRadius > 10f) + { + blurPass = (int)Passes.ShapeHighQuality; + blurAndMergePass = (int)Passes.ShapeHighQualityMerge; + } + else if (maxRadius > 5f) + { + blurPass = (int)Passes.ShapeMediumQuality; + blurAndMergePass = (int)Passes.ShapeMediumQualityMerge; + } + else + { + blurPass = (int)Passes.ShapeLowQuality; + blurAndMergePass = (int)Passes.ShapeLowQualityMerge; + } + } + else + { + if (maxRadius > 10f) + { + blurPass = (int)Passes.ShapeHighQualityDilateFg; + blurAndMergePass = (int)Passes.ShapeHighQualityMergeDilateFg; + } + else if (maxRadius > 5f) + { + blurPass = (int)Passes.ShapeMediumQualityDilateFg; + blurAndMergePass = (int)Passes.ShapeMediumQualityMergeDilateFg; + } + else + { + blurPass = (int)Passes.ShapeLowQualityDilateFg; + blurAndMergePass = (int)Passes.ShapeLowQualityMergeDilateFg; + } + } + } + } +} diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/DepthOfField/DepthOfField.cs.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/DepthOfField/DepthOfField.cs.meta new file mode 100644 index 0000000..c12eba8 --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/DepthOfField/DepthOfField.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 8a338d679868f45439ea43c7ae035e36 +timeCreated: 1453985420 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: + - m_FilmicDepthOfFieldShader: {fileID: 4800000, guid: bff0e5458fb914f5c9985ba4f09171d2, + type: 3} + - m_MedianFilterShader: {fileID: 4800000, guid: a058b22d4123add4b807e832604e5e7b, + type: 3} + - m_TextureBokehShader: {fileID: 4800000, guid: c961b8ed1f00f924d804ada5143bd0e8, + type: 3} + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/DepthOfField/Editor.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/DepthOfField/Editor.meta new file mode 100644 index 0000000..79c6494 --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/DepthOfField/Editor.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 1a8273952ce5743428d8c42b25cb0458 +folderAsset: yes +timeCreated: 1449046242 +licenseType: Store +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/DepthOfField/Editor/DepthOfFieldEditor.cs b/IronToad_UnityProject/Assets/Standard Assets/Effects/DepthOfField/Editor/DepthOfFieldEditor.cs new file mode 100644 index 0000000..9d9e327 --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/DepthOfField/Editor/DepthOfFieldEditor.cs @@ -0,0 +1,139 @@ +using UnityEditor; +using UnityEngine; + +namespace UnityStandardAssets.CinematicEffects +{ + [CustomEditor(typeof(DepthOfField))] + class DepthOfFieldEditor : Editor + { + private SerializedProperty m_VisualizeFocus; + private SerializedProperty m_TweakMode; + private SerializedProperty m_FilteringQuality; + private SerializedProperty m_ApertureShape; + private SerializedProperty m_ApertureOrientation; + + private SerializedProperty m_Transform; + private SerializedProperty m_FocusPlane; + private SerializedProperty m_Range; + private SerializedProperty m_NearPlane; + private SerializedProperty m_NearFalloff; + private SerializedProperty m_FarPlane; + private SerializedProperty m_FarFalloff; + private SerializedProperty m_NearBlurRadius; + private SerializedProperty m_FarBlurRadius; + + private SerializedProperty m_Texture; + private SerializedProperty m_Scale; + private SerializedProperty m_Intensity; + private SerializedProperty m_Threshold; + private SerializedProperty m_SpawnHeuristic; + + private void OnEnable() + { + var o = serializedObject; + + m_VisualizeFocus = o.FindProperty("settings.visualizeFocus"); + m_TweakMode = o.FindProperty("settings.tweakMode"); + m_FilteringQuality = o.FindProperty("settings.filteringQuality"); + m_ApertureShape = o.FindProperty("settings.apertureShape"); + m_ApertureOrientation = o.FindProperty("settings.apertureOrientation"); + + m_Transform = o.FindProperty("focus.transform"); + m_FocusPlane = o.FindProperty("focus.focusPlane"); + m_Range = o.FindProperty("focus.range"); + m_NearPlane = o.FindProperty("focus.nearPlane"); + m_NearFalloff = o.FindProperty("focus.nearFalloff"); + m_FarPlane = o.FindProperty("focus.farPlane"); + m_FarFalloff = o.FindProperty("focus.farFalloff"); + m_NearBlurRadius = o.FindProperty("focus.nearBlurRadius"); + m_FarBlurRadius = o.FindProperty("focus.farBlurRadius"); + + m_Texture = o.FindProperty("bokehTexture.texture"); + m_Scale = o.FindProperty("bokehTexture.scale"); + m_Intensity = o.FindProperty("bokehTexture.intensity"); + m_Threshold = o.FindProperty("bokehTexture.threshold"); + m_SpawnHeuristic = o.FindProperty("bokehTexture.spawnHeuristic"); + } + + public override void OnInspectorGUI() + { + serializedObject.Update(); + + EditorGUILayout.PropertyField(m_VisualizeFocus); + EditorGUILayout.PropertyField(m_TweakMode); + EditorGUILayout.PropertyField(m_FilteringQuality); + EditorGUILayout.PropertyField(m_ApertureShape); + + if (m_ApertureShape.intValue != (int)DepthOfField.ApertureShape.Circular) + { + EditorGUI.indentLevel++; + EditorGUILayout.PropertyField(m_ApertureOrientation, new GUIContent("Orientation")); + EditorGUI.indentLevel--; + } + + EditorGUILayout.Space(); + EditorGUILayout.LabelField("Focus", EditorStyles.boldLabel); + + var falloff = new GUIContent("Falloff"); + var blurRadius = new GUIContent("Blur Radius"); + + EditorGUI.indentLevel++; + + if (m_TweakMode.intValue == (int)DepthOfField.TweakMode.Range) + { + EditorGUILayout.PropertyField(m_Transform); + + using (new EditorGUI.DisabledGroupScope(m_Transform.objectReferenceValue != null)) + { + EditorGUILayout.PropertyField(m_FocusPlane); + } + + EditorGUILayout.PropertyField(m_Range); + + EditorGUILayout.LabelField(m_NearPlane.displayName); + EditorGUI.indentLevel++; + EditorGUILayout.PropertyField(m_NearFalloff, falloff); + EditorGUILayout.PropertyField(m_NearBlurRadius, blurRadius); + EditorGUI.indentLevel--; + + EditorGUILayout.LabelField(m_FarPlane.displayName); + EditorGUI.indentLevel++; + EditorGUILayout.PropertyField(m_FarFalloff, falloff); + EditorGUILayout.PropertyField(m_FarBlurRadius, blurRadius); + EditorGUI.indentLevel--; + } + else + { + EditorGUILayout.PropertyField(m_NearPlane); + EditorGUI.indentLevel++; + EditorGUILayout.PropertyField(m_NearFalloff, falloff); + EditorGUILayout.PropertyField(m_NearBlurRadius, blurRadius); + EditorGUI.indentLevel--; + + EditorGUILayout.PropertyField(m_FarPlane); + EditorGUI.indentLevel++; + EditorGUILayout.PropertyField(m_FarFalloff, falloff); + EditorGUILayout.PropertyField(m_FarBlurRadius, blurRadius); + EditorGUI.indentLevel--; + } + + EditorGUI.indentLevel--; + + EditorGUILayout.Space(); + EditorGUILayout.LabelField("Bokeh", EditorStyles.boldLabel); + + EditorGUI.indentLevel++; + EditorGUILayout.PropertyField(m_Texture); + if (m_Texture.objectReferenceValue != null) + { + EditorGUILayout.PropertyField(m_Scale); + EditorGUILayout.PropertyField(m_Intensity); + EditorGUILayout.PropertyField(m_Threshold); + EditorGUILayout.PropertyField(m_SpawnHeuristic); + } + EditorGUI.indentLevel--; + + serializedObject.ApplyModifiedProperties(); + } + } +} diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/DepthOfField/Editor/DepthOfFieldEditor.cs.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/DepthOfField/Editor/DepthOfFieldEditor.cs.meta new file mode 100644 index 0000000..92f56d3 --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/DepthOfField/Editor/DepthOfFieldEditor.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 3eb07ef5681934662814cc768bcdb60c +timeCreated: 1429220270 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/DepthOfField/Helpers.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/DepthOfField/Helpers.meta new file mode 100644 index 0000000..5e30d18 --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/DepthOfField/Helpers.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 5427d9a5126366c42b9509de8233bff7 +folderAsset: yes +timeCreated: 1453985653 +licenseType: Store +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/DepthOfField/Helpers/HexShape.psd b/IronToad_UnityProject/Assets/Standard Assets/Effects/DepthOfField/Helpers/HexShape.psd new file mode 100644 index 0000000000000000000000000000000000000000..eef48cbe86b6b9047c7772f43abdaeded1bcc333 GIT binary patch literal 478144 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�ac0WR6N^*{V8-(sYK?Q~1m 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�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 NfBXOc-~SgR@P92b81Dc8 literal 0 HcmV?d00001 diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/DepthOfField/Helpers/HexShape.psd.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/DepthOfField/Helpers/HexShape.psd.meta new file mode 100644 index 0000000..c46144f --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/DepthOfField/Helpers/HexShape.psd.meta @@ -0,0 +1,55 @@ +fileFormatVersion: 2 +guid: a4cdca73d61814d33ac1587f6c163bca +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + linearTexture: 0 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + cubemapConvolution: 0 + cubemapConvolutionSteps: 7 + cubemapConvolutionExponent: 1.5 + seamlessCubemap: 0 + textureFormat: -1 + maxTextureSize: 64 + textureSettings: + filterMode: -1 + aniso: 0 + mipBias: -1 + wrapMode: 1 + nPOTScale: 1 + lightmap: 0 + rGBM: 0 + compressionQuality: 50 + allowsAlphaSplitting: 0 + 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 + alphaIsTransparency: 0 + textureType: -1 + buildTargetSettings: [] + spriteSheet: + sprites: [] + outline: [] + spritePackingTag: + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/DepthOfField/Helpers/RoundedHexShape.tif b/IronToad_UnityProject/Assets/Standard Assets/Effects/DepthOfField/Helpers/RoundedHexShape.tif new file mode 100644 index 0000000000000000000000000000000000000000..9dccaf371735626d2e2867a0d8d713b7021e9978 GIT binary patch literal 32876 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 literal 0 HcmV?d00001 diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/DepthOfField/Helpers/RoundedHexShape.tif.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/DepthOfField/Helpers/RoundedHexShape.tif.meta new file mode 100644 index 0000000..46b330b --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/DepthOfField/Helpers/RoundedHexShape.tif.meta @@ -0,0 +1,57 @@ +fileFormatVersion: 2 +guid: 9014ef007a9a1d545b0fba20daa0fc7c +timeCreated: 1454425451 +licenseType: Store +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + linearTexture: 0 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 1 + generateCubemap: 0 + cubemapConvolution: 0 + cubemapConvolutionSteps: 7 + cubemapConvolutionExponent: 1.5 + seamlessCubemap: 0 + textureFormat: -1 + maxTextureSize: 64 + textureSettings: + filterMode: -1 + aniso: 0 + mipBias: -1 + wrapMode: 1 + nPOTScale: 1 + lightmap: 0 + rGBM: 0 + compressionQuality: 50 + allowsAlphaSplitting: 0 + 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 + alphaIsTransparency: 0 + textureType: -1 + buildTargetSettings: [] + spriteSheet: + sprites: [] + outline: [] + spritePackingTag: + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/DepthOfField/Helpers/SphereShape.psd b/IronToad_UnityProject/Assets/Standard Assets/Effects/DepthOfField/Helpers/SphereShape.psd new file mode 100644 index 0000000000000000000000000000000000000000..a100649160719b85b695058e36dcc0d725bdcf69 GIT binary patch literal 492716 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∋_-ezr-! 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

3??#;yu$@u` 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 U= 1.0) return BOKEH_ZERO_VEC; + if(uv.y <= 0.0) return BOKEH_ZERO_VEC; if(uv.y >= 1.0) return BOKEH_ZERO_VEC; + #endif + return BOKEH_ONE_VEC; + } + + struct vs_out + { + float4 pos : SV_POSITION; + float2 uv : TEXCOORD0; + float4 color : TEXCOORD1; + float cocOverlap : TEXCOORD2; + }; + + struct appdata + { + float4 vertex : POSITION; + float2 texcoord : TEXCOORD0; + }; + + struct v2f + { + float4 pos : SV_POSITION; + float2 uv_flip : TEXCOORD0; + float2 uv : TEXCOORD1; + }; + + AppendStructuredBuffer pointBufferOutput : register(u1); + StructuredBuffer pointBuffer; + + vs_out vertApply (uint id : SV_VertexID) + { + vs_out o = (vs_out)0; + float2 pos = pointBuffer[id].pos.xy ; + o.pos = float4(pos * 2.0 - 1.0, 0.0, 1.0); + o.color = pointBuffer[id].color; + + #if UNITY_UV_STARTS_AT_TOP + o.pos.y *= -1.0; + #endif + + o.cocOverlap = pointBuffer[id].pos.z; + + return o; + } + + v2f vertCollect (appdata v) + { + v2f o; + o.pos = mul (UNITY_MATRIX_MVP, v.vertex); + o.uv = v.texcoord; + o.uv_flip = v.texcoord; + + #if UNITY_UV_STARTS_AT_TOP + if (_MainTex_TexelSize.y < 0.0) + { + o.uv_flip.y = 1.0 - o.uv_flip.y; + o.pos.y *= -1.0; + } + #endif + + return o; + } + + [maxvertexcount(4)] + void geom (point vs_out input[1], inout TriangleStream outStream) + { + // NEW ENERGY CONSERVATION: + float2 scale2 = _BokehParams.ww * input[0].color.aa * _BokehParams.xx; + float4 offs = 0.0; + offs.xy = float2(3.0, 3.0) + 2.0 * floor(scale2 + float2(0.5, 0.5)); + + float2 rs = ((float2(1.0, 1.0) + 2.0 * (scale2 + float2(0.5, 0.5))));; + float2 f2 = offs.xy / rs; + + float energyAdjustment = (_BokehParams.y) / (rs.x * rs.y); + offs.xy *= _Screen.xy; + + gs_out output; + + output.pos = input[0].pos + offs * float4(-1.0, 1.0, 0.0, 0.0); + output.misc = float4(f2, 0.0, 0.0); + output.uv = float3(0.0, 1.0, input[0].cocOverlap); + output.color = input[0].color * energyAdjustment; + outStream.Append (output); + + output.pos = input[0].pos + offs*float4(1.0, 1.0, 0.0, 0.0); + output.misc = float4(f2, 0.0, 0.0); + output.uv = float3(1.0, 1.0, input[0].cocOverlap); + output.color = input[0].color * energyAdjustment; + outStream.Append (output); + + output.pos = input[0].pos + offs*float4(-1.0, -1.0, 0.0, 0.0); + output.misc = float4(f2, 0.0, 0.0); + output.uv = float3(0.0, 0.0, input[0].cocOverlap); + output.color = input[0].color * energyAdjustment; + outStream.Append (output); + + output.pos = input[0].pos + offs*float4(1.0, -1.0, 0.0, 0.0); + output.misc = float4(f2, 0.0, 0.0); + output.uv = float3(1.0, 0.0, input[0].cocOverlap); + output.color = input[0].color * energyAdjustment; + outStream.Append (output); + + outStream.RestartStrip(); + } + + float4 collectBrightPixel(half2 uv) + { + half4 c = tex2D(_MainTex, uv); + half coc = abs(c.a); + half lumc = Luminance(c.rgb); + + half4 cblurred = tex2D(_BlurredColor, uv); + half cocBlurred = abs(cblurred.a); + half lumblurred = Luminance(cblurred.rgb); + half fgCoc = -min(c.a, 0.0); + + [branch] + if (coc * _BokehParams.w > 1.0 && cocBlurred > 0.1 && lumc > _BokehParams.z && abs(lumc - lumblurred) > _SpawnHeuristic) + { + appendStruct append = (appendStruct)0; + append.pos = float3(uv, fgCoc); + append.color.rgba = half4(c.rgb * saturate(coc * 4.0), coc); + pointBufferOutput.Append(append); + c = half4(c.rgb * saturate(1.0 - coc * 4.0), c.a); + } + + return c; + } + + ENDCG + + SubShader + { + // Pass 0: bokeh splatting + Pass + { + ZWrite Off ZTest Always Cull Off + BlendOp Add, Add + Blend DstAlpha One, Zero One + ColorMask RGBA + + CGPROGRAM + + #pragma target 5.0 + #pragma vertex vertApply + #pragma geometry geom + #pragma fragment frag + + fixed4 frag (gs_out i) : SV_Target + { + float2 uv = (i.uv.xy) * i.misc.xy + (float2(1,1)-i.misc.xy) * 0.5; // smooth uv scale + return float4(i.color.rgb, 1) * float4(tex2D(_MainTex, uv.xy).rgb, i.uv.z) * clampBorderColor (uv); + } + + ENDCG + } + + // Pass 1: append buffer "collect" + Pass + { + ZWrite Off ZTest Always Cull Off + + CGPROGRAM + + #pragma vertex vertCollect + #pragma fragment frag + #pragma target 5.0 + + float4 frag (v2f i) : SV_Target + { + return collectBrightPixel(i.uv); + } + + ENDCG + } + } + + Fallback Off +} diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/DepthOfField/Resources/BokehSplatting.shader.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/DepthOfField/Resources/BokehSplatting.shader.meta new file mode 100644 index 0000000..36cccae --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/DepthOfField/Resources/BokehSplatting.shader.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: c961b8ed1f00f924d804ada5143bd0e8 +timeCreated: 1449750679 +licenseType: Store +ShaderImporter: + defaultTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/DepthOfField/Resources/DepthOfField.shader b/IronToad_UnityProject/Assets/Standard Assets/Effects/DepthOfField/Resources/DepthOfField.shader new file mode 100644 index 0000000..5914588 --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/DepthOfField/Resources/DepthOfField.shader @@ -0,0 +1,1221 @@ +Shader "Hidden/DepthOfField/DepthOfField" +{ + Properties + { + _MainTex ("-", 2D) = "black" + _SecondTex ("-", 2D) = "black" + _ThirdTex ("-", 2D) = "black" + } + + CGINCLUDE + + #pragma target 3.0 + #pragma fragmentoption ARB_precision_hint_fastest + #include "UnityCG.cginc" + + // Undef USE_LOCAL_TONEMAPPING if you dont want to use local tonemapping. + // Tweaking these values down will trade stability for less bokeh (see Tonemap/TonemapInvert methods below). + #ifndef SHADER_API_MOBILE + #define USE_LOCAL_TONEMAPPING + #endif + #define LOCAL_TONEMAP_START_LUMA 1.0 + #define LOCAL_TONEMAP_RANGE_LUMA 5.0 + + sampler2D _SecondTex; + sampler2D _ThirdTex; + + uniform half4 _MainTex_TexelSize; + uniform half4 _BlurCoe; + uniform half4 _BlurParams; + uniform half4 _Convolved_TexelSize; + uniform float4 _Offsets; + + uniform half4 _MainTex_ST; + uniform half4 _SecondTex_ST; + uniform half4 _ThirdTex_ST; + + #if (SHADER_TARGET >= 50 && !defined(SHADER_API_PSSL)) + #define USE_TEX2DOBJECT_FOR_COC + #endif + + #if defined(USE_TEX2DOBJECT_FOR_COC) + Texture2D _CameraDepthTexture; + SamplerState sampler_CameraDepthTexture; + Texture2D _MainTex; + SamplerState sampler_MainTex; + #else + sampler2D _MainTex; + sampler2D _CameraDepthTexture; + #endif + + /////////////////////////////////////////////////////////////////////////////// + // Verter Shaders and declaration + /////////////////////////////////////////////////////////////////////////////// + + struct v2f + { + float4 pos : SV_POSITION; + float2 uv : TEXCOORD0; + float2 uv1 : TEXCOORD1; + }; + + struct v2fDepth + { + half4 pos : SV_POSITION; + half2 uv : TEXCOORD0; + }; + + struct v2fBlur + { + float4 pos : SV_POSITION; + float2 uv : TEXCOORD0; + float4 uv01 : TEXCOORD1; + float4 uv23 : TEXCOORD2; + float4 uv45 : TEXCOORD3; + float4 uv67 : TEXCOORD4; + float4 uv89 : TEXCOORD5; + }; + + v2fDepth vert(appdata_img v) + { + v2fDepth o; + o.pos = mul(UNITY_MATRIX_MVP, v.vertex); + o.uv = v.texcoord.xy; + + #if UNITY_UV_STARTS_AT_TOP + if (_MainTex_TexelSize.y < 0.0) + o.uv.y = 1.0 - o.uv.y; + #endif + + return o; + } + + v2fDepth vertNoFlip(appdata_img v) + { + v2fDepth o; + o.pos = mul(UNITY_MATRIX_MVP, v.vertex); + o.uv = v.texcoord.xy; + return o; + } + + v2f vert_d(appdata_img v) + { + v2f o; + o.pos = mul (UNITY_MATRIX_MVP, v.vertex); + o.uv1.xy = v.texcoord.xy; + o.uv.xy = v.texcoord.xy; + + #if UNITY_UV_STARTS_AT_TOP + if (_MainTex_TexelSize.y < 0.0) + o.uv.y = 1.0 - o.uv.y; + #endif + + return o; + } + + v2f vertFlip(appdata_img v) + { + v2f o; + o.pos = mul (UNITY_MATRIX_MVP, v.vertex); + o.uv1.xy = v.texcoord.xy; + o.uv.xy = v.texcoord.xy; + + #if UNITY_UV_STARTS_AT_TOP + if (_MainTex_TexelSize.y < 0.0) + { + o.uv.y = 1.0 - o.uv.y; + o.uv1.y = 1.0 - o.uv1.y; + } + #endif + + return o; + } + + v2fBlur vertBlurPlusMinus(appdata_img v) + { + v2fBlur o; + o.pos = mul(UNITY_MATRIX_MVP, v.vertex); + o.uv.xy = v.texcoord.xy; + o.uv01 = v.texcoord.xyxy + _Offsets.xyxy * float4(1,1, -1,-1) * _MainTex_TexelSize.xyxy / 6.0; + o.uv23 = v.texcoord.xyxy + _Offsets.xyxy * float4(2,2, -2,-2) * _MainTex_TexelSize.xyxy / 6.0; + o.uv45 = v.texcoord.xyxy + _Offsets.xyxy * float4(3,3, -3,-3) * _MainTex_TexelSize.xyxy / 6.0; + o.uv67 = v.texcoord.xyxy + _Offsets.xyxy * float4(4,4, -4,-4) * _MainTex_TexelSize.xyxy / 6.0; + o.uv89 = v.texcoord.xyxy + _Offsets.xyxy * float4(5,5, -5,-5) * _MainTex_TexelSize.xyxy / 6.0; + return o; + } + + /////////////////////////////////////////////////////////////////////////////// + // Helpers + /////////////////////////////////////////////////////////////////////////////// + + inline half4 FetchMainTex(float2 uv) + { + #if defined(USE_TEX2DOBJECT_FOR_COC) + return _MainTex.SampleLevel(sampler_MainTex, uv, 0.0); + #else + return tex2Dlod(_MainTex, float4(uv, 0.0, 0.0)); + #endif + } + + inline half2 GetBilinearFetchTexOffsetFromAbsCoc(half4 absCoc) + { + half4 cocWeights = absCoc * absCoc * absCoc; + + half2 offset = 0.0; + offset += cocWeights.r * float2(-1.0, 1.0); + offset += cocWeights.g * float2( 1.0, 1.0); + offset += cocWeights.b * float2( 1.0,-1.0); + offset += cocWeights.a * float2(-1.0,-1.0); + offset = clamp((half2)-1.0,(half2)1.0, offset); + offset *= 0.5; + return offset; + } + + inline half4 FetchColorAndCocFromMainTex(float2 uv, float2 offsetFromKernelCenter) + { + // Bilinear + half4 fetch = FetchMainTex(uv); + + // CoC can't be linearly interpolated while doing "scatter and gather" or we will have haloing where coc vary sharply. + #if defined(USE_TEX2DOBJECT_FOR_COC) + half4 allCoc = _MainTex.GatherAlpha(sampler_MainTex, uv); + half cocAB = (abs(allCoc.r) < abs(allCoc.g)) ? allCoc.r : allCoc.g; + half cocCD = (abs(allCoc.b) < abs(allCoc.a)) ? allCoc.b : allCoc.a; + half coc = (abs(cocAB) < abs(cocCD)) ? cocAB : cocCD; + #else + // No gather available -> instead point sample the coc from the fartest away texel (not as good). + half2 bilinearCenter = floor(uv * _MainTex_TexelSize.zw - 0.5) + 1.0; + half2 cocUV = bilinearCenter + 0.5 * sign(offsetFromKernelCenter); + half coc = tex2Dlod(_MainTex, float4(cocUV * _MainTex_TexelSize.xy, 0.0, 0.0)).a; + #endif + + fetch.a = coc; + return fetch; + } + + inline half GetCocFromZValue(half d) + { + d = Linear01Depth(d); + half coc = d < _BlurCoe.z + ? clamp((_BlurParams.x * d + _BlurParams.y), -1.0, 0.0) + : saturate((_BlurParams.z * d + _BlurParams.w)); + return coc; + } + + inline half GetCocFromDepth(half2 uv) + { + #if defined(USE_TEX2DOBJECT_FOR_COC) + half d = _CameraDepthTexture.SampleLevel(sampler_CameraDepthTexture, uv, 0.0); + #else + half d = SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, uv); + #endif + return GetCocFromZValue(d); + } + + #if (SHADER_TARGET < 50 && !defined(SHADER_API_PSSL)) + half rcp(half x) + { + return 1.0 / x; + } + #endif + + // From http://graphicrants.blogspot.dk/2013/12/tone-mapping.html + inline half3 Tonemap(half3 color) + { + #ifdef USE_LOCAL_TONEMAPPING + half a = LOCAL_TONEMAP_START_LUMA; + half b = LOCAL_TONEMAP_RANGE_LUMA; + + half luma = max(color.r, max(color.g, color.b)); + if (luma <= a) + return color; + + return color * rcp(luma) * (a * a - b * luma) / (2.0 * a - b - luma); + #else + return color; + #endif + } + + inline half3 TonemapInvert(half3 color) + { + #ifdef USE_LOCAL_TONEMAPPING + half a = LOCAL_TONEMAP_START_LUMA; + half b = LOCAL_TONEMAP_RANGE_LUMA; + + half luma = max(color.r, max(color.g, color.b)); + if (luma <= a) + return color; + + return color * rcp(luma) * (a * a - (2.0 * a - b) * luma) / (b - luma); + #else + return color; + #endif + } + + + /////////////////////////////////////////////////////////////////////////////// + // Directional (hexagonal/octogonal) bokeh + /////////////////////////////////////////////////////////////////////////////// + + #define SAMPLE_NUM_L 6 + #define SAMPLE_NUM_M 11 + #define SAMPLE_NUM_H 16 + + inline half4 shapeDirectionalBlur(half2 uv, bool mergePass, int numSample, bool sampleDilatedFG) + { + half4 centerTap = FetchMainTex(uv); + half fgCoc = centerTap.a; + half fgBlendFromPreviousPass = centerTap.a * _Offsets.z; + + if (sampleDilatedFG) + { + half2 cocs = tex2Dlod(_SecondTex, half4(uv, 0.0, 0.0)).rg; + fgCoc = min(cocs.r, cocs.g); + centerTap.a = cocs.g; + } + + half bgRadius = smoothstep(0.0, 0.85, centerTap.a) * _BlurCoe.y; + half fgRadius = smoothstep(0.0, 0.85, -fgCoc) * _BlurCoe.x; + half radius = max(bgRadius, fgRadius); + + if (radius < 1e-2) + return half4(centerTap.rgb, (sampleDilatedFG || mergePass) ? fgBlendFromPreviousPass : centerTap.a); + + half radOtherFgRad = radius / (fgRadius + 1e-2); + half radOtherBgRad = radius / (bgRadius + 1e-2); + half2 range = radius * _MainTex_TexelSize.xy; + + half fgWeight = 1e-3; + half bgWeight = 1e-3; + half3 fgSum = half3(0.0, 0.0, 0.0); + half3 bgSum = half3(0.0, 0.0, 0.0); + + for (int k = 0; k < numSample; k++) + { + half t = (half)k / half(numSample - 1.0); + half2 kVal = lerp(_Offsets.xy, -_Offsets.xy, t); + half2 offset = kVal * range; + half2 texCoord = uv + offset; + half4 sample0 = FetchColorAndCocFromMainTex(texCoord, offset); + + if (sampleDilatedFG) + sample0.a = tex2Dlod(_SecondTex, half4(texCoord, 0.0, 0.0)).g; + + half dist = abs(2.0 * t - 1.0); + half distanceFactor = saturate(-0.5 * abs(sample0.a - centerTap.a) * dist + 1.0); + half isNear = max(0.0, -sample0.a); + half isFar = max(0.0, sample0.a) * distanceFactor; + isNear *= 1.0 - smoothstep(1.0, 2.0, dist * radOtherFgRad); + isFar *= 1.0 - smoothstep(1.0, 2.0, dist * radOtherBgRad); + + fgWeight += isNear; + fgSum += sample0.rgb * isNear; + bgWeight += isFar; + bgSum += sample0.rgb * isFar; + } + + half3 fgColor = fgSum / (fgWeight + 1e-4); + half3 bgColor = bgSum / (bgWeight + 1e-4); + half bgBlend = saturate(2.0 * bgWeight / numSample); + half fgBlend = saturate(2.0 * fgWeight / numSample); + + half3 finalBg = lerp(centerTap.rgb, bgColor, bgBlend); + half3 finalColor = lerp(finalBg, fgColor, max(max(0.0 , -centerTap.a), fgBlend)); + + if (mergePass) + finalColor = min(finalColor, tex2Dlod(_ThirdTex, half4(uv, 0.0, 0.0)).rgb); + + finalColor = lerp(centerTap.rgb, finalColor, saturate(bgBlend + fgBlend)); + fgBlend = max(fgBlendFromPreviousPass, fgBlend); + return half4(finalColor, (sampleDilatedFG || mergePass) ? fgBlend : centerTap.a); + } + + half4 fragShapeLowQuality(v2fDepth i) : SV_Target + { + return shapeDirectionalBlur(i.uv, false, SAMPLE_NUM_L, false); + } + + half4 fragShapeLowQualityDilateFg(v2fDepth i) : SV_Target + { + return shapeDirectionalBlur(i.uv, false, SAMPLE_NUM_L, true); + } + + half4 fragShapeLowQualityMerge(v2fDepth i) : SV_Target + { + return shapeDirectionalBlur(i.uv, true, SAMPLE_NUM_L, false); + } + + half4 fragShapeLowQualityMergeDilateFg(v2fDepth i) : SV_Target + { + return shapeDirectionalBlur(i.uv, true, SAMPLE_NUM_L, true); + } + + half4 fragShapeMediumQuality(v2fDepth i) : SV_Target + { + return shapeDirectionalBlur(i.uv, false, SAMPLE_NUM_M, false); + } + + half4 fragShapeMediumQualityDilateFg(v2fDepth i) : SV_Target + { + return shapeDirectionalBlur(i.uv, false, SAMPLE_NUM_M, true); + } + + half4 fragShapeMediumQualityMerge(v2fDepth i) : SV_Target + { + return shapeDirectionalBlur(i.uv, true, SAMPLE_NUM_M, false); + } + + half4 fragShapeMediumQualityMergeDilateFg(v2fDepth i) : SV_Target + { + return shapeDirectionalBlur(i.uv, true, SAMPLE_NUM_M, true); + } + + half4 fragShapeHighQuality(v2fDepth i) : SV_Target + { + return shapeDirectionalBlur(i.uv, false, SAMPLE_NUM_H, false); + } + + half4 fragShapeHighQualityDilateFg(v2fDepth i) : SV_Target + { + return shapeDirectionalBlur(i.uv, false, SAMPLE_NUM_H, true); + } + + half4 fragShapeHighQualityMerge(v2fDepth i) : SV_Target + { + return shapeDirectionalBlur(i.uv, true, SAMPLE_NUM_H, false); + } + + half4 fragShapeHighQualityMergeDilateFg(v2fDepth i) : SV_Target + { + return shapeDirectionalBlur(i.uv, true, SAMPLE_NUM_H, true); + } + + /////////////////////////////////////////////////////////////////////////////// + // Disk Bokeh + /////////////////////////////////////////////////////////////////////////////// + + static const half3 DiscBokeh48[48] = + { + // 48 tap regularly spaced circular kernel (x,y, length) + // Fill free to change the shape to try other bokehs style :) + half3( 0.99144h, 0.13053h, 1.0h), + half3( 0.92388h, 0.38268h, 1.0h), + half3( 0.79335h, 0.60876h, 1.0h), + half3( 0.60876h, 0.79335h, 1.0h), + half3( 0.38268h, 0.92388h, 1.0h), + half3( 0.13053h, 0.99144h, 1.0h), + half3(-0.13053h, 0.99144h, 1.0h), + half3(-0.38268h, 0.92388h, 1.0h), + half3(-0.60876h, 0.79335h, 1.0h), + half3(-0.79335h, 0.60876h, 1.0h), + half3(-0.92388h, 0.38268h, 1.0h), + half3(-0.99144h, 0.13053h, 1.0h), + half3(-0.99144h,-0.13053h, 1.0h), + half3(-0.92388h,-0.38268h, 1.0h), + half3(-0.79335h,-0.60876h, 1.0h), + half3(-0.60876h,-0.79335h, 1.0h), + half3(-0.38268h,-0.92388h, 1.0h), + half3(-0.13053h,-0.99144h, 1.0h), + half3( 0.13053h,-0.99144h, 1.0h), + half3( 0.38268h,-0.92388h, 1.0h), + half3( 0.60876h,-0.79335h, 1.0h), + half3( 0.79335h,-0.60876h, 1.0h), + half3( 0.92388h,-0.38268h, 1.0h), + half3( 0.99144h,-0.13053h, 1.0h), + half3( 0.64732h, 0.12876h, 0.66h), + half3( 0.54877h, 0.36668h, 0.66h), + half3( 0.36668h, 0.54877h, 0.66h), + half3( 0.12876h, 0.64732h, 0.66h), + half3(-0.12876h, 0.64732h, 0.66h), + half3(-0.36668h, 0.54877h, 0.66h), + half3(-0.54877h, 0.36668h, 0.66h), + half3(-0.64732h, 0.12876h, 0.66h), + half3(-0.64732h,-0.12876h, 0.66h), + half3(-0.54877h,-0.36668h, 0.66h), + half3(-0.36668h,-0.54877h, 0.66h), + half3(-0.12876h,-0.64732h, 0.66h), + half3( 0.12876h,-0.64732h, 0.66h), + half3( 0.36668h,-0.54877h, 0.66h), + half3( 0.54877h,-0.36668h, 0.66h), + half3( 0.64732h,-0.12876h, 0.66h), + half3( 0.30488h, 0.12629h, 0.33h), + half3( 0.12629h, 0.30488h, 0.33h), + half3(-0.12629h, 0.30488h, 0.33h), + half3(-0.30488h, 0.12629h, 0.33h), + half3(-0.30488h,-0.12629h, 0.33h), + half3(-0.12629h,-0.30488h, 0.33h), + half3( 0.12629h,-0.30488h, 0.33h), + half3( 0.30488h,-0.12629h, 0.33h) + }; + + inline half4 circleCocBokeh(half2 uv, bool sampleDilatedFG, int increment) + { + half4 centerTap = FetchMainTex(uv); + half fgCoc = centerTap.a; + + if (sampleDilatedFG) + fgCoc = min(tex2Dlod(_SecondTex, half4(uv, 0.0, 0.0)).r, fgCoc); + + half bgRadius = 0.5 * smoothstep(0.0, 0.85, centerTap.a) * _BlurCoe.y; + half fgRadius = 0.5 * smoothstep(0.0, 0.85, -fgCoc) * _BlurCoe.x; + half radius = max(bgRadius, fgRadius); + + if (radius < 1e-2) + return half4(centerTap.rgb, 0.0); + + half2 poissonScale = radius * _MainTex_TexelSize.xy; + half fgWeight = max(0.0,-centerTap.a); + half bgWeight = max(0.0, centerTap.a); + half3 fgSum = centerTap.rgb * fgWeight; + half3 bgSum = centerTap.rgb * bgWeight; + + half radOtherFgRad = radius / (fgRadius + 1e-2); + half radOtherBgRad = radius / (bgRadius + 1e-2); + + for (int l = 0; l < 48; l += increment) + { + half2 sampleUV = uv + DiscBokeh48[l].xy * poissonScale.xy; + half4 sample0 = FetchColorAndCocFromMainTex(sampleUV, DiscBokeh48[l].xy); + + half isNear = max(0.0, -sample0.a); + half distanceFactor = saturate(-0.5 * abs(sample0.a - centerTap.a) * DiscBokeh48[l].z + 1.0); + half isFar = max(0.0, sample0.a) * distanceFactor; + isNear *= 1.0 - smoothstep(1.0, 2.0, DiscBokeh48[l].z * radOtherFgRad); + isFar *= 1.0 - smoothstep(1.0, 2.0, DiscBokeh48[l].z * radOtherBgRad); + + fgWeight += isNear; + fgSum += sample0.rgb * isNear; + bgWeight += isFar; + bgSum += sample0.rgb * isFar; + } + + half3 fgColor = fgSum / (fgWeight + 1e-4); + half3 bgColor = bgSum / (bgWeight + 1e-4); + half bgBlend = saturate(2.0 * bgWeight / 49.0); + half fgBlend = saturate(2.0 * fgWeight / 49.0); + + half3 finalBg = lerp(centerTap.rgb, bgColor, bgBlend); + half3 finalColor = lerp(finalBg, fgColor, max(max(0.0 , -centerTap.a), fgBlend)); + half4 returnValue = half4(finalColor, fgBlend); + + return returnValue; + } + + half4 fragCircleBlurWithDilatedFg(v2fDepth i) : SV_Target + { + return circleCocBokeh(i.uv, true, 1); + } + + half4 fragCircleBlur(v2fDepth i) : SV_Target + { + return circleCocBokeh(i.uv, false, 1); + } + + half4 fragCircleBlurWithDilatedFgLowQuality(v2fDepth i) : SV_Target + { + return circleCocBokeh(i.uv, true, 2); + } + + half4 fragCircleBlurLowQuality(v2fDepth i) : SV_Target + { + return circleCocBokeh(i.uv, false, 2); + } + + /////////////////////////////////////////////////////////////////////////////// + // Prefilter blur + /////////////////////////////////////////////////////////////////////////////// + + #define DISC_PREFILTER_SAMPLE 9 + static const half2 DiscPrefilter[DISC_PREFILTER_SAMPLE] = + { + half2(0.01288369, 0.5416069), + half2(-0.9192798, -0.09529364), + half2( 0.7596578, 0.1922738), + half2( -0.14132, -0.2880242), + half2(-0.5249333, 0.7777638), + half2(-0.5871695, -0.7403569), + half2( 0.3202196, -0.6442268), + half2( 0.8553214, -0.3920982), + half2( 0.5827708, 0.7599297) + }; + + half4 fragCocPrefilter(v2fDepth i) : SV_Target + { + half4 centerTap = FetchMainTex(i.uv); + half radius = 0.33 * 0.5 * (centerTap.a < 0.0 + ? -(centerTap.a * _BlurCoe.x) + : (centerTap.a * _BlurCoe.y)); + half2 poissonScale = radius * _MainTex_TexelSize.xy; + + if (radius < 1e-2) + return centerTap; + + half sampleCount = 1.0; + half3 sum = centerTap.rgb; + + for (int l = 0; l < DISC_PREFILTER_SAMPLE; l++) + { + half2 sampleUV = i.uv + DiscPrefilter[l].xy * poissonScale.xy; + half4 sample0 = FetchColorAndCocFromMainTex(sampleUV, DiscPrefilter[l].xy); + half weight = max(sample0.a * centerTap.a, 0.0); + sum += sample0.rgb * weight; + sampleCount += weight; + } + + half4 returnValue = half4(sum / sampleCount, centerTap.a); + return returnValue; + } + + /////////////////////////////////////////////////////////////////////////////// + // Final merge and upsample + /////////////////////////////////////////////////////////////////////////////// + + inline half4 upSampleConvolved(half2 uv) + { + half2 convolvedTexelPos = uv * _Convolved_TexelSize.xy; + half2 convolvedTexelCenter = floor( convolvedTexelPos ) + 0.5; + half2 convolvedTexelOffsetFromCenter = convolvedTexelPos - convolvedTexelCenter; + half2 offsetFromCoc = half2(0.0, 0.0); + + #if defined(USE_TEX2DOBJECT_FOR_COC) + half2 cocUV = (convolvedTexelOffsetFromCenter * _Convolved_TexelSize.zw) + uv; + half4 coc = _CameraDepthTexture.GatherRed(sampler_CameraDepthTexture, cocUV); + coc.r = GetCocFromZValue(coc.r); + coc.g = GetCocFromZValue(coc.g); + coc.b = GetCocFromZValue(coc.b); + coc.a = GetCocFromZValue(coc.a); + + half4 absCoc = abs(coc); + offsetFromCoc = GetBilinearFetchTexOffsetFromAbsCoc(absCoc) * 0.5; + uv += offsetFromCoc * _Convolved_TexelSize.zw; + #endif + + /* + // Bicubic upsampling (B-spline) - Uncomment me for higher quality upsampling + // Adding offsetFromCoc "antialias" haloing from bright in focus region on dark out of focus region. + // However its a hack as we should consider all the COC of the bicubic region and kill the bicubic + // interpolation to avoid in any leaking but that would be too expensive, so when this is a problem + // one should rather disable bicubic interpolation. + half2 f = convolvedTexelOffsetFromCenter + offsetFromCoc; + half2 f2 = f * f; + half2 f3 = f * f2; + + half2 w0 = -0.166 * f3 + 0.5 * f2 - 0.5 * f + 0.166; + half2 w1 = 0.5 * f3 - f2 + 0.666; + half2 w3 = 0.166 * f3; + half2 w2 = 1.0 - w0 - w1 - w3; + + half2 s0 = w0 + w1; + half2 s1 = w2 + w3; + half2 f0 = w1 / s0; + half2 f1 = w3 / s1; + + half2 t0 = _Convolved_TexelSize.zw * (convolvedTexelCenter - 1.0 + f0); + half2 t1 = _Convolved_TexelSize.zw * (convolvedTexelCenter + 1.0 + f1); + + return tex2Dlod(_SecondTex, half4(t0.x, t0.y, 0.0, 0.0)) * s0.x * s0.y + + tex2Dlod(_SecondTex, half4(t1.x, t0.y, 0.0, 0.0)) * s1.x * s0.y + + tex2Dlod(_SecondTex, half4(t0.x, t1.y, 0.0, 0.0)) * s0.x * s1.y + + tex2Dlod(_SecondTex, half4(t1.x, t1.y, 0.0, 0.0)) * s1.x * s1.y; + */ + + return tex2Dlod(_SecondTex, half4(uv, 0.0, 0.0)); + } + + inline half4 dofMerge(half2 uv) + { + half4 convolvedTap = upSampleConvolved(uv); + convolvedTap.rgb = TonemapInvert(convolvedTap.rgb); + + half4 sourceTap = FetchMainTex(uv); + half coc = GetCocFromDepth(uv); + + coc = (coc * _BlurCoe.y > 1.0) ? coc : 0.0; + half blendValue = smoothstep(0.0, 0.33, max(coc, convolvedTap.a)); + half3 returnValue = lerp(sourceTap.rgb, convolvedTap.rgb, blendValue); + return (blendValue < 1e-2) ? sourceTap : half4(returnValue.rgb, sourceTap.a); + } + + half4 fragMergeExplicit(v2fDepth i) : SV_Target + { + return dofMerge(i.uv); + } + + /////////////////////////////////////////////////////////////////////////////// + // Downsampling and COC computation + /////////////////////////////////////////////////////////////////////////////// + + inline half4 captureCoc(half2 uvColor, half2 uvDepth) + { + /*****************/ + /* coc.a | coc.b */ + /* coc.r | coc.g */ + /*****************/ + #if defined(USE_TEX2DOBJECT_FOR_COC) + half4 coc = _CameraDepthTexture.GatherRed(sampler_CameraDepthTexture, uvDepth); + coc.r = GetCocFromZValue(coc.r); + coc.g = GetCocFromZValue(coc.g); + coc.b = GetCocFromZValue(coc.b); + coc.a = GetCocFromZValue(coc.a); + #else + half4 coc; + coc.r = GetCocFromDepth(uvDepth + _MainTex_TexelSize.xy * half2(-0.25, 0.25)); + coc.g = GetCocFromDepth(uvDepth + _MainTex_TexelSize.xy * half2( 0.25, 0.25)); + coc.b = GetCocFromDepth(uvDepth + _MainTex_TexelSize.xy * half2( 0.25,-0.25)); + coc.a = GetCocFromDepth(uvDepth + _MainTex_TexelSize.xy * half2(-0.25,-0.25)); + #endif + + half4 absCoc = abs(coc); + half2 offset = GetBilinearFetchTexOffsetFromAbsCoc(absCoc) * _MainTex_TexelSize.xy; + half4 color = FetchMainTex(uvColor + offset); + + half cocRG = (absCoc.r> m_GroupFields = new Dictionary>(); + + private LensAberrations concreteTarget + { + get { return target as LensAberrations; } + } + + private void PopulateMap(FieldInfo group) + { + var searchPath = group.Name + "."; + foreach (var setting in group.FieldType.GetFields(BindingFlags.Instance | BindingFlags.Public)) + { + List settingsGroup; + if (!m_GroupFields.TryGetValue(group, out settingsGroup)) + { + settingsGroup = new List(); + m_GroupFields[group] = settingsGroup; + } + + var property = serializedObject.FindProperty(searchPath + setting.Name); + if (property != null) + settingsGroup.Add(property); + } + } + + private void OnEnable() + { + var settingsGroups = typeof(LensAberrations).GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance).Where(x => x.GetCustomAttributes(typeof(LensAberrations.SettingsGroup), false).Any()); + + foreach (var settingGroup in settingsGroups) + PopulateMap(settingGroup); + } + + private void DrawFields() + { + foreach (var group in m_GroupFields) + { + var enabledField = group.Value.FirstOrDefault(x => x.propertyPath == group.Key.Name + ".enabled"); + var groupProperty = serializedObject.FindProperty(group.Key.Name); + + GUILayout.Space(5); + bool display = EditorGUIHelper.Header(groupProperty, enabledField); + if (!display) + continue; + + GUILayout.BeginHorizontal(); + { + GUILayout.Space(10); + GUILayout.BeginVertical(); + { + GUILayout.Space(3); + foreach (var field in group.Value.Where(x => x.propertyPath != group.Key.Name + ".enabled")) + { + EditorGUILayout.PropertyField(field); + } + } + GUILayout.EndVertical(); + } + GUILayout.EndHorizontal(); + } + } + + public override void OnInspectorGUI() + { + serializedObject.Update(); + DrawFields(); + serializedObject.ApplyModifiedProperties(); + } + } +} diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/LensAberrations/Editor/LensAberrationsEditor.cs.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/LensAberrations/Editor/LensAberrationsEditor.cs.meta new file mode 100644 index 0000000..b72f52e --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/LensAberrations/Editor/LensAberrationsEditor.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 8becb41f431ef90468376f6c5845e0bd +timeCreated: 1454680396 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/LensAberrations/LensAberrations.cs b/IronToad_UnityProject/Assets/Standard Assets/Effects/LensAberrations/LensAberrations.cs new file mode 100644 index 0000000..2f3cca7 --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/LensAberrations/LensAberrations.cs @@ -0,0 +1,311 @@ +using UnityEngine; +using System; + +namespace UnityStandardAssets.CinematicEffects +{ + [ExecuteInEditMode] + [RequireComponent(typeof(Camera))] + [AddComponentMenu("Image Effects/Cinematic/Lens Aberrations")] + public class LensAberrations : MonoBehaviour + { + #region Attributes + [AttributeUsage(AttributeTargets.Field)] + public class SettingsGroup : Attribute + {} + + [AttributeUsage(AttributeTargets.Field)] + public class AdvancedSetting : Attribute + {} + #endregion + + #region Settings + [Serializable] + public struct DistortionSettings + { + public bool enabled; + + [Range(-100f, 100f), Tooltip("Distortion amount.")] + public float amount; + + [Range(-1f, 1f), Tooltip("Distortion center point (X axis).")] + public float centerX; + + [Range(-1f, 1f), Tooltip("Distortion center point (Y axis).")] + public float centerY; + + [Range(0f, 1f), Tooltip("Amount multiplier on X axis. Set it to 0 to disable distortion on this axis.")] + public float amountX; + + [Range(0f, 1f), Tooltip("Amount multiplier on Y axis. Set it to 0 to disable distortion on this axis.")] + public float amountY; + + [Range(0.01f, 5f), Tooltip("Global screen scaling.")] + public float scale; + + public static DistortionSettings defaultSettings + { + get + { + return new DistortionSettings + { + enabled = false, + amount = 0f, + centerX = 0f, + centerY = 0f, + amountX = 1f, + amountY = 1f, + scale = 1f + }; + } + } + } + + [Serializable] + public struct VignetteSettings + { + public bool enabled; + + [ColorUsage(false)] + [Tooltip("Vignette color. Use the alpha channel for transparency.")] + public Color color; + + [Tooltip("Sets the vignette center point (screen center is [0.5,0.5]).")] + public Vector2 center; + + [Range(0f, 3f), Tooltip("Amount of vignetting on screen.")] + public float intensity; + + [Range(0.01f, 3f), Tooltip("Smoothness of the vignette borders.")] + public float smoothness; + + [AdvancedSetting, Range(0f, 1f), Tooltip("Lower values will make a square-ish vignette.")] + public float roundness; + + [Range(0f, 1f), Tooltip("Blurs the corners of the screen. Leave this at 0 to disable it.")] + public float blur; + + [Range(0f, 1f), Tooltip("Desaturate the corners of the screen. Leave this to 0 to disable it.")] + public float desaturate; + + public static VignetteSettings defaultSettings + { + get + { + return new VignetteSettings + { + enabled = false, + color = new Color(0f, 0f, 0f, 1f), + center = new Vector2(0.5f, 0.5f), + intensity = 1.4f, + smoothness = 0.8f, + roundness = 1f, + blur = 0f, + desaturate = 0f + }; + } + } + } + + [Serializable] + public struct ChromaticAberrationSettings + { + public bool enabled; + + [ColorUsage(false)] + [Tooltip("Channels to apply chromatic aberration to.")] + public Color color; + + [Range(-50f, 50f)] + [Tooltip("Amount of tangential distortion.")] + public float amount; + + public static ChromaticAberrationSettings defaultSettings + { + get + { + return new ChromaticAberrationSettings + { + enabled = false, + color = Color.green, + amount = 0f + }; + } + } + } + #endregion + + [SettingsGroup] + public DistortionSettings distortion = DistortionSettings.defaultSettings; + + [SettingsGroup] + public VignetteSettings vignette = VignetteSettings.defaultSettings; + + [SettingsGroup] + public ChromaticAberrationSettings chromaticAberration = ChromaticAberrationSettings.defaultSettings; + + private enum Pass + { + BlurPrePass, + Chroma, + Distort, + Vignette, + ChromaDistort, + ChromaVignette, + DistortVignette, + ChromaDistortVignette + } + + [SerializeField] + private Shader m_Shader; + public Shader shader + { + get + { + if (m_Shader == null) + m_Shader = Shader.Find("Hidden/LensAberrations"); + + return m_Shader; + } + } + + private Material m_Material; + public Material material + { + get + { + if (m_Material == null) + m_Material = ImageEffectHelper.CheckShaderAndCreateMaterial(shader); + + return m_Material; + } + } + + private RenderTextureUtility m_RTU; + + private void OnEnable() + { + if (!ImageEffectHelper.IsSupported(shader, false, false, this)) + enabled = false; + + m_RTU = new RenderTextureUtility(); + } + + private void OnDisable() + { + if (m_Material != null) + DestroyImmediate(m_Material); + + m_Material = null; + m_RTU.ReleaseAllTemporaryRenderTextures(); + } + + private void OnRenderImage(RenderTexture source, RenderTexture destination) + { + if (!vignette.enabled && !chromaticAberration.enabled && !distortion.enabled) + { + Graphics.Blit(source, destination); + return; + } + + material.shaderKeywords = null; + + if (distortion.enabled) + { + float amount = 1.6f * Math.Max(Mathf.Abs(distortion.amount), 1f); + float theta = 0.01745329251994f * Math.Min(160f, amount); + float sigma = 2f * Mathf.Tan(theta * 0.5f); + var p0 = new Vector4(distortion.centerX, distortion.centerY, Mathf.Max(distortion.amountX, 1e-4f), Mathf.Max(distortion.amountY, 1e-4f)); + var p1 = new Vector3(distortion.amount >= 0f ? theta : 1f / theta, sigma, 1f / distortion.scale); + material.EnableKeyword(distortion.amount >= 0f ? "DISTORT" : "UNDISTORT"); + material.SetVector("_DistCenterScale", p0); + material.SetVector("_DistAmount", p1); + } + + if (chromaticAberration.enabled) + { + material.EnableKeyword("CHROMATIC_ABERRATION"); + var chromaParams = new Vector4(chromaticAberration.color.r, chromaticAberration.color.g, chromaticAberration.color.b, chromaticAberration.amount * 0.001f); + material.SetVector("_ChromaticAberration", chromaParams); + } + + if (vignette.enabled) + { + material.SetColor("_VignetteColor", vignette.color); + + if (vignette.blur > 0f) + { + // Downscale + gaussian blur (2 passes) + int w = source.width / 2; + int h = source.height / 2; + var rt1 = m_RTU.GetTemporaryRenderTexture(w, h, 0, source.format); + var rt2 = m_RTU.GetTemporaryRenderTexture(w, h, 0, source.format); + + material.SetVector("_BlurPass", new Vector2(1f / w, 0f)); + Graphics.Blit(source, rt1, material, (int)Pass.BlurPrePass); + + if (distortion.enabled) + { + material.DisableKeyword("DISTORT"); + material.DisableKeyword("UNDISTORT"); + } + + material.SetVector("_BlurPass", new Vector2(0f, 1f / h)); + Graphics.Blit(rt1, rt2, material, (int)Pass.BlurPrePass); + + material.SetVector("_BlurPass", new Vector2(1f / w, 0f)); + Graphics.Blit(rt2, rt1, material, (int)Pass.BlurPrePass); + material.SetVector("_BlurPass", new Vector2(0f, 1f / h)); + Graphics.Blit(rt1, rt2, material, (int)Pass.BlurPrePass); + + material.SetTexture("_BlurTex", rt2); + material.SetFloat("_VignetteBlur", vignette.blur * 3f); + material.EnableKeyword("VIGNETTE_BLUR"); + + if (distortion.enabled) + material.EnableKeyword(distortion.amount >= 0f ? "DISTORT" : "UNDISTORT"); + } + + if (vignette.desaturate > 0f) + { + material.EnableKeyword("VIGNETTE_DESAT"); + material.SetFloat("_VignetteDesat", 1f - vignette.desaturate); + } + + material.SetVector("_VignetteCenter", vignette.center); + + if (Mathf.Approximately(vignette.roundness, 1f)) + { + material.EnableKeyword("VIGNETTE_CLASSIC"); + material.SetVector("_VignetteSettings", new Vector2(vignette.intensity, vignette.smoothness)); + } + else + { + material.EnableKeyword("VIGNETTE_FILMIC"); + float roundness = (1f - vignette.roundness) * 6f + vignette.roundness; + material.SetVector("_VignetteSettings", new Vector3(vignette.intensity, vignette.smoothness, roundness)); + } + } + + int pass = 0; + + if (vignette.enabled && chromaticAberration.enabled && distortion.enabled) + pass = (int)Pass.ChromaDistortVignette; + else if (vignette.enabled && chromaticAberration.enabled) + pass = (int)Pass.ChromaVignette; + else if (vignette.enabled && distortion.enabled) + pass = (int)Pass.DistortVignette; + else if (chromaticAberration.enabled && distortion.enabled) + pass = (int)Pass.ChromaDistort; + else if (vignette.enabled) + pass = (int)Pass.Vignette; + else if (chromaticAberration.enabled) + pass = (int)Pass.Chroma; + else if (distortion.enabled) + pass = (int)Pass.Distort; + + Graphics.Blit(source, destination, material, pass); + + m_RTU.ReleaseAllTemporaryRenderTextures(); + } + } +} diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/LensAberrations/LensAberrations.cs.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/LensAberrations/LensAberrations.cs.meta new file mode 100644 index 0000000..49f8d7d --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/LensAberrations/LensAberrations.cs.meta @@ -0,0 +1,13 @@ +fileFormatVersion: 2 +guid: ff5335a7357baa3489a469d0ca0f40f3 +timeCreated: 1454589487 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: + - m_Shader: {fileID: 4800000, guid: 136ab50fe2b9ad64d9c22adc3668abb7, type: 3} + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/LensAberrations/Resources.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/LensAberrations/Resources.meta new file mode 100644 index 0000000..f75b438 --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/LensAberrations/Resources.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 6580025651e0f284489694492cf3ce61 +folderAsset: yes +timeCreated: 1454583120 +licenseType: Store +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/LensAberrations/Resources/LensAberrations.shader b/IronToad_UnityProject/Assets/Standard Assets/Effects/LensAberrations/Resources/LensAberrations.shader new file mode 100644 index 0000000..4a38b3a --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/LensAberrations/Resources/LensAberrations.shader @@ -0,0 +1,293 @@ +Shader "Hidden/LensAberrations" +{ + Properties + { + _MainTex ("Texture", 2D) = "white" {} + } + SubShader + { + ZTest Always Cull Off ZWrite Off + Fog { Mode off } + + CGINCLUDE + + #pragma fragmentoption ARB_precision_hint_fastest + #include "UnityCG.cginc" + #pragma target 3.0 + + sampler2D _MainTex; + float4 _MainTex_TexelSize; + + half4 _ChromaticAberration; + + half4 chromaticAberration(half2 uv) + { + half2 coords = 2.0 * uv - 1.0; + half2 cd = coords * dot(coords, coords); + half4 color = tex2D(_MainTex, uv); + half3 fringe = tex2D(_MainTex, uv - cd * _ChromaticAberration.a).rgb; + color.rgb = lerp(color.rgb, fringe, _ChromaticAberration.rgb); + return color; + } + + half4 _DistCenterScale; + half3 _DistAmount; + + half2 distort(half2 uv) + { + uv = (uv - 0.5) * _DistAmount.z + 0.5; + half2 ruv = _DistCenterScale.zw * (uv - 0.5 - _DistCenterScale.xy); + half ru = length(ruv); + + #if DISTORT + + half wu = ru * _DistAmount.x; + ru = tan(wu) * (1.0 / (ru * _DistAmount.y)); + uv = uv + ruv * (ru - 1.0); + + #elif UNDISTORT + + ru = (1.0 / ru) * _DistAmount.x * atan(ru * _DistAmount.y); + uv = uv + ruv * (ru - 1.0); + + #endif + + return uv; + } + + half3 _VignetteColor; + half3 _VignetteSettings; + half2 _VignetteCenter; + half _VignetteBlur; + half _VignetteDesat; + sampler2D _BlurTex; + + half4 vignette(half4 color, half2 uv) + { + #define _Intensity _VignetteSettings.x + #define _Smoothness _VignetteSettings.y + #define _Roundness _VignetteSettings.z + + half vfactor = 1.0; + + #if VIGNETTE_CLASSIC + + half2 d = (uv - _VignetteCenter) * _Intensity; + vfactor = pow(saturate(1.0 - dot(d, d)), _Smoothness); + + #else + + half2 d = abs(uv - _VignetteCenter) * _Intensity; + d = pow(d, _Roundness); + + #endif + + vfactor = pow(saturate(1.0 - dot(d, d)), _Smoothness); + + #if VIGNETTE_BLUR + + half2 coords = 2.0 * uv - 1.0; + half3 blur = tex2D(_BlurTex, uv).rgb; + color.rgb = lerp(color.rgb, blur, saturate(_VignetteBlur * dot(coords, coords))); + + #endif + + #if VIGNETTE_DESAT + + half lum = Luminance(color); + color.rgb = lerp(lerp(lum.xxx, color.rgb, _VignetteDesat), color.rgb, vfactor); + + #endif + + color.rgb *= lerp(_VignetteColor, (1.0).xxx, vfactor); + + return color; + } + + ENDCG + + // (0) Blur pre-pass + Pass + { + CGPROGRAM + #pragma vertex vert_blur_prepass + #pragma fragment frag_blur_prepass + #pragma multi_compile __ CHROMATIC_ABERRATION + #pragma multi_compile __ DISTORT UNDISTORT + #pragma + + half2 _BlurPass; + + struct v2f + { + half4 pos : SV_POSITION; + half2 uv : TEXCOORD0; + half4 uv1 : TEXCOORD1; + half4 uv2 : TEXCOORD2; + }; + + v2f vert_blur_prepass(appdata_img v) + { + v2f o; + o.pos = mul(UNITY_MATRIX_MVP, v.vertex); + o.uv = v.texcoord.xy; + + #if UNITY_UV_STARTS_AT_TOP + if (_MainTex_TexelSize.y < 0) + o.uv.y = 1.0 - o.uv.y; + #endif + + half2 d1 = 1.3846153846 * _BlurPass; + half2 d2 = 3.2307692308 * _BlurPass; + o.uv1 = half4(o.uv + d1, o.uv - d1); + o.uv2 = half4(o.uv + d2, o.uv - d2); + return o; + } + + half4 fetch(half2 uv) + { + #if (DISTORT || UNDISTORT) + uv = distort(uv); + #endif + + #if CHROMATIC_ABERRATION + return chromaticAberration(uv); + #else + return tex2D(_MainTex, uv); + #endif + } + + half4 frag_blur_prepass(v2f i) : SV_Target + { + half4 c = fetch(i.uv) * 0.2270270270; + c += fetch(i.uv1.xy) * 0.3162162162; + c += fetch(i.uv1.zw) * 0.3162162162; + c += fetch(i.uv2.xy) * 0.0702702703; + c += fetch(i.uv2.zw) * 0.0702702703; + return c; + } + ENDCG + } + + // (1) Chroma + Pass + { + CGPROGRAM + #pragma vertex vert_img + #pragma fragment frag + + half4 frag(v2f_img i) : SV_Target + { + return chromaticAberration(i.uv); + } + ENDCG + } + + // (2) Distort + Pass + { + CGPROGRAM + #pragma vertex vert_img + #pragma fragment frag + #pragma multi_compile DISTORT UNDISTORT + + half4 frag(v2f_img i) : SV_Target + { + half2 uv = distort(i.uv); + return tex2D(_MainTex, uv); + } + ENDCG + } + + // (3) Vignette + Pass + { + CGPROGRAM + #pragma vertex vert_img + #pragma fragment frag + #pragma multi_compile VIGNETTE_CLASSIC VIGNETTE_FILMIC + #pragma multi_compile __ VIGNETTE_BLUR + #pragma multi_compile __ VIGNETTE_DESAT + + half4 frag(v2f_img i) : SV_Target + { + half4 color = tex2D(_MainTex, i.uv); + return vignette(color, i.uv); + } + ENDCG + } + + // (4) Chroma / Distort + Pass + { + CGPROGRAM + #pragma vertex vert_img + #pragma fragment frag + #pragma multi_compile DISTORT UNDISTORT + + half4 frag(v2f_img i) : SV_Target + { + half2 uv = distort(i.uv); + return chromaticAberration(uv); + } + ENDCG + } + + // (5) Chroma / Vignette + Pass + { + CGPROGRAM + #pragma vertex vert_img + #pragma fragment frag + #pragma multi_compile VIGNETTE_CLASSIC VIGNETTE_FILMIC + #pragma multi_compile __ VIGNETTE_BLUR + #pragma multi_compile __ VIGNETTE_DESAT + + half4 frag(v2f_img i) : SV_Target + { + return vignette(chromaticAberration(i.uv), i.uv); + } + ENDCG + } + + // (6) Distort / Vignette + Pass + { + CGPROGRAM + #pragma vertex vert_img + #pragma fragment frag + #pragma multi_compile DISTORT UNDISTORT + #pragma multi_compile VIGNETTE_CLASSIC VIGNETTE_FILMIC + #pragma multi_compile __ VIGNETTE_BLUR + #pragma multi_compile __ VIGNETTE_DESAT + + half4 frag(v2f_img i) : SV_Target + { + half2 uv = distort(i.uv); + return vignette(tex2D(_MainTex, uv), i.uv); + } + ENDCG + } + + // (6) Chroma / Distort / Vignette + Pass + { + CGPROGRAM + #pragma vertex vert_img + #pragma fragment frag + #pragma multi_compile DISTORT UNDISTORT + #pragma multi_compile VIGNETTE_CLASSIC VIGNETTE_FILMIC + #pragma multi_compile __ VIGNETTE_BLUR + #pragma multi_compile __ VIGNETTE_DESAT + + half4 frag(v2f_img i) : SV_Target + { + half2 uv = distort(i.uv); + half4 chroma = chromaticAberration(uv); + return vignette(chroma, i.uv); + } + ENDCG + } + } + FallBack off +} diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/LensAberrations/Resources/LensAberrations.shader.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/LensAberrations/Resources/LensAberrations.shader.meta new file mode 100644 index 0000000..915929c --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/LensAberrations/Resources/LensAberrations.shader.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 136ab50fe2b9ad64d9c22adc3668abb7 +timeCreated: 1454583143 +licenseType: Store +ShaderImporter: + defaultTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/ScreenSpaceReflection.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/ScreenSpaceReflection.meta new file mode 100644 index 0000000..1c8f804 --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/ScreenSpaceReflection.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 0190f05cacbdca84c932a2f2e0035c51 +folderAsset: yes +timeCreated: 1448358989 +licenseType: Store +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/ScreenSpaceReflection/Editor.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/ScreenSpaceReflection/Editor.meta new file mode 100644 index 0000000..48b2c1b --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/ScreenSpaceReflection/Editor.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 4834a3e1213004b48b14703e6723c17c +folderAsset: yes +timeCreated: 1448359076 +licenseType: Store +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/ScreenSpaceReflection/Editor/ScreenSpaceReflectionEditor.cs b/IronToad_UnityProject/Assets/Standard Assets/Effects/ScreenSpaceReflection/Editor/ScreenSpaceReflectionEditor.cs new file mode 100644 index 0000000..000bafa --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/ScreenSpaceReflection/Editor/ScreenSpaceReflectionEditor.cs @@ -0,0 +1,117 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; +using System.Reflection; +using UnityEditor; +using UnityEngine; + +namespace UnityStandardAssets.CinematicEffects +{ + [CustomPropertyDrawer(typeof(ScreenSpaceReflection.SSRSettings.LayoutAttribute))] + public class LayoutDrawer : PropertyDrawer + { + private const float kHeadingSpace = 22.0f; + + static Styles m_Styles; + + private class Styles + { + public readonly GUIStyle header = "ShurikenModuleTitle"; + + internal Styles() + { + header.font = (new GUIStyle("Label")).font; + header.border = new RectOffset(15, 7, 4, 4); + header.fixedHeight = kHeadingSpace; + header.contentOffset = new Vector2(20f, -2f); + } + } + + public override float GetPropertyHeight(SerializedProperty property, GUIContent label) + { + if (!property.isExpanded) + return kHeadingSpace; + + var count = property.CountInProperty(); + return EditorGUIUtility.singleLineHeight * count + 15; + } + + public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) + { + if (m_Styles == null) + m_Styles = new Styles(); + + position.height = EditorGUIUtility.singleLineHeight; + property.isExpanded = Header(position, property.displayName, property.isExpanded); + position.y += kHeadingSpace; + + if (!property.isExpanded) + return; + + foreach (SerializedProperty child in property) + { + EditorGUI.PropertyField(position, child); + position.y += EditorGUIUtility.singleLineHeight; + } + } + + private bool Header(Rect position, String title, bool display) + { + Rect rect = position; + position.height = EditorGUIUtility.singleLineHeight; + GUI.Box(rect, title, m_Styles.header); + + Rect toggleRect = new Rect(rect.x + 4f, rect.y + 2f, 13f, 13f); + if (Event.current.type == EventType.Repaint) + EditorStyles.foldout.Draw(toggleRect, false, false, display, false); + + Event e = Event.current; + if (e.type == EventType.MouseDown && rect.Contains(e.mousePosition)) + { + display = !display; + e.Use(); + } + return display; + } + } + + [CustomEditor(typeof(ScreenSpaceReflection))] + internal class ScreenSpaceReflectionEditor : Editor + { + [NonSerialized] + private List m_Properties = new List(); + + void OnEnable() + { + var settings = FieldFinder.GetField(x => x.settings); + foreach (var setting in settings.FieldType.GetFields()) + { + var prop = settings.Name + "." + setting.Name; + m_Properties.Add(serializedObject.FindProperty(prop)); + } + } + + public override void OnInspectorGUI() + { + serializedObject.Update(); + + EditorGUILayout.Space(); + + // move into the m_Settings fields... + foreach (var property in m_Properties) + EditorGUILayout.PropertyField(property); + + serializedObject.ApplyModifiedProperties(); + } + + private void Apply(ScreenSpaceReflection.SSRSettings settings) + { + var validTargets = targets.Where(x => x is ScreenSpaceReflection).Cast().ToArray(); + + Undo.RecordObjects(validTargets, "Apply SSR Settings"); + foreach (var validTarget in validTargets) + validTarget.settings = settings; + } + } +} diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/ScreenSpaceReflection/Editor/ScreenSpaceReflectionEditor.cs.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/ScreenSpaceReflection/Editor/ScreenSpaceReflectionEditor.cs.meta new file mode 100644 index 0000000..8ed616c --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/ScreenSpaceReflection/Editor/ScreenSpaceReflectionEditor.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: eb0236f80884a1f4793c96b4d2da5c68 +timeCreated: 1446039760 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/ScreenSpaceReflection/Resources.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/ScreenSpaceReflection/Resources.meta new file mode 100644 index 0000000..3481967 --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/ScreenSpaceReflection/Resources.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: a19e50b158b32e6458d43c13406863ff +folderAsset: yes +timeCreated: 1453972687 +licenseType: Store +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/ScreenSpaceReflection/Resources/ScreenSpaceRaytrace.cginc b/IronToad_UnityProject/Assets/Standard Assets/Effects/ScreenSpaceReflection/Resources/ScreenSpaceRaytrace.cginc new file mode 100644 index 0000000..24f95d4 --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/ScreenSpaceReflection/Resources/ScreenSpaceRaytrace.cginc @@ -0,0 +1,243 @@ +/** +\author Michael Mara and Morgan McGuire, Casual Effects. 2015. +*/ + +#ifndef SCREEN_SPACE_RAYTRACE_INCLUDED +#define SCREEN_SPACE_RAYTRACE_INCLUDED + + +sampler2D_float _CameraDepthTexture; + + +float distanceSquared(float2 A, float2 B) +{ + A -= B; + return dot(A, A); +} + +float distanceSquared(float3 A, float3 B) +{ + A -= B; + return dot(A, A); +} + +void swap(inout float v0, inout float v1) +{ + float temp = v0; + v0 = v1; + v1 = temp; +} + + +bool isIntersecting(float rayZMin, float rayZMax, float sceneZ, float layerThickness) +{ + return (rayZMax >= sceneZ - layerThickness) && (rayZMin <= sceneZ); +} + +void rayIterations(in bool traceBehindObjects, inout float2 P, inout float stepDirection, inout float end, inout int stepCount, inout int maxSteps, inout bool intersecting, + inout float sceneZ, inout float2 dP, inout float3 Q, inout float3 dQ, inout float k, inout float dk, + inout float rayZMin, inout float rayZMax, inout float prevZMaxEstimate, inout bool permute, inout float2 hitPixel, + inout float2 invSize, inout float layerThickness) +{ + bool stop = intersecting; + + UNITY_LOOP + + for (; (P.x * stepDirection) <= end && stepCount < maxSteps && !stop; P += dP, Q.z += dQ.z, k += dk, stepCount += 1) + { + // The depth range that the ray covers within this loop iteration. + // Assume that the ray is moving in increasing z and swap if backwards. + rayZMin = prevZMaxEstimate; + //rayZMin = (dQ.z * -0.5 + Q.z) / (dk * -0.5 + k); + // Compute the value at 1/2 pixel into the future + rayZMax = (dQ.z * 0.5 + Q.z) / (dk * 0.5 + k); + prevZMaxEstimate = rayZMax; + + if (rayZMin > rayZMax) + { + swap(rayZMin, rayZMax); + } + + // Undo the homogeneous operation to obtain the camera-space + // Q at each point + hitPixel = permute ? P.yx : P; + + sceneZ = tex2Dlod(_CameraDepthTexture, float4(hitPixel * invSize,0,0)).r; + sceneZ = -LinearEyeDepth(sceneZ); + + bool isBehind = (rayZMin <= sceneZ); + intersecting = isBehind && (rayZMax >= sceneZ - layerThickness); + stop = traceBehindObjects ? intersecting : isBehind; + + } // pixel on ray + + P -= dP, Q.z -= dQ.z, k -= dk; +} + +/** + \param csOrigin must have z < -0.01, and project within the valid screen rectangle + \param stepRate Set to 1.0 by default, higher to step faster + */ +bool castDenseScreenSpaceRay + (float3 csOrigin, + float3 csDirection, + float4x4 projectToPixelMatrix, + float2 csZBufferSize, + float3 clipInfo, + float jitterFraction, + int maxSteps, + float layerThickness, + float maxRayTraceDistance, + out float2 hitPixel, + int stepRate, + bool traceBehindObjects, + out float3 csHitPoint, + out float stepCount) { + + float2 invSize = float2(1.0 / csZBufferSize.x, 1.0 / csZBufferSize.y); + + // Initialize to off screen + hitPixel = float2(-1, -1); + + float nearPlaneZ = -0.01; + // Clip ray to a near plane in 3D (doesn't have to be *the* near plane, although that would be a good idea) + float rayLength = ((csOrigin.z + csDirection.z * maxRayTraceDistance) > nearPlaneZ) ? + ((nearPlaneZ - csOrigin.z) / csDirection.z) : + maxRayTraceDistance; + + float3 csEndPoint = csDirection * rayLength + csOrigin; + + // Project into screen space + // This matrix has a lot of zeroes in it. We could expand + // out these multiplies to avoid multiplying by zero + // ...but 16 MADDs are not a big deal compared to what's ahead + float4 H0 = mul(projectToPixelMatrix, float4(csOrigin, 1.0)); + float4 H1 = mul(projectToPixelMatrix, float4(csEndPoint, 1.0)); + + // There are a lot of divisions by w that can be turned into multiplications + // at some minor precision loss...and we need to interpolate these 1/w values + // anyway. + // + // Because the caller was required to clip to the near plane, + // this homogeneous division (projecting from 4D to 2D) is guaranteed + // to succeed. + float k0 = 1.0 / H0.w; + float k1 = 1.0 / H1.w; + + // Screen-space endpoints + float2 P0 = H0.xy * k0; + float2 P1 = H1.xy * k1; + + // Switch the original points to values that interpolate linearly in 2D: + float3 Q0 = csOrigin * k0; + float3 Q1 = csEndPoint * k1; + +#if 1 // Clipping to the screen coordinates. We could simply modify maxSteps instead + float yMax = csZBufferSize.y - 0.5; + float yMin = 0.5; + float xMax = csZBufferSize.x - 0.5; + float xMin = 0.5; + + // 2D interpolation parameter + float alpha = 0.0; + // P0 must be in bounds + if (P1.y > yMax || P1.y < yMin) { + float yClip = (P1.y > yMax) ? yMax : yMin; + float yAlpha = (P1.y - yClip) / (P1.y - P0.y); // Denominator is not zero, since P0 != P1 (or P0 would have been clipped!) + alpha = yAlpha; + } + + // P0 must be in bounds + if (P1.x > xMax || P1.x < xMin) { + float xClip = (P1.x > xMax) ? xMax : xMin; + float xAlpha = (P1.x - xClip) / (P1.x - P0.x); // Denominator is not zero, since P0 != P1 (or P0 would have been clipped!) + alpha = max(alpha, xAlpha); + } + + // These are all in homogeneous space, so they interpolate linearly + P1 = lerp(P1, P0, alpha); + k1 = lerp(k1, k0, alpha); + Q1 = lerp(Q1, Q0, alpha); +#endif + + // We're doing this to avoid divide by zero (rays exactly parallel to an eye ray) + P1 = (distanceSquared(P0, P1) < 0.0001) ? P0 + float2(0.01, 0.01) : P1; + + float2 delta = P1 - P0; + + // Assume horizontal + bool permute = false; + if (abs(delta.x) < abs(delta.y)) { + // More-vertical line. Create a permutation that swaps x and y in the output + permute = true; + + // Directly swizzle the inputs + delta = delta.yx; + P1 = P1.yx; + P0 = P0.yx; + } + + // From now on, "x" is the primary iteration direction and "y" is the secondary one + + float stepDirection = sign(delta.x); + float invdx = stepDirection / delta.x; + float2 dP = float2(stepDirection, invdx * delta.y); + + // Track the derivatives of Q and k + float3 dQ = (Q1 - Q0) * invdx; + float dk = (k1 - k0) * invdx; + + dP *= stepRate; + dQ *= stepRate; + dk *= stepRate; + + P0 += dP * jitterFraction; + Q0 += dQ * jitterFraction; + k0 += dk * jitterFraction; + + // Slide P from P0 to P1, (now-homogeneous) Q from Q0 to Q1, and k from k0 to k1 + float3 Q = Q0; + float k = k0; + + // We track the ray depth at +/- 1/2 pixel to treat pixels as clip-space solid + // voxels. Because the depth at -1/2 for a given pixel will be the same as at + // +1/2 for the previous iteration, we actually only have to compute one value + // per iteration. + float prevZMaxEstimate = csOrigin.z; + stepCount = 0.0; + float rayZMax = prevZMaxEstimate, rayZMin = prevZMaxEstimate; + float sceneZ = 100000; + + // P1.x is never modified after this point, so pre-scale it by + // the step direction for a signed comparison + float end = P1.x * stepDirection; + + bool intersecting = isIntersecting(rayZMin, rayZMax, sceneZ, layerThickness); + // We only advance the z field of Q in the inner loop, since + // Q.xy is never used until after the loop terminates + + //int rayIterations = min(maxSteps, stepsToGetOffscreen); + + + float2 P = P0; + + int originalStepCount = 0; + rayIterations(traceBehindObjects, P, stepDirection, end, originalStepCount, maxSteps, intersecting, + sceneZ, dP, Q, dQ, k, dk, + rayZMin, rayZMax, prevZMaxEstimate, permute, hitPixel, + invSize, layerThickness); + + + stepCount = originalStepCount; + + // Loop only advanced the Z component. Now that we know where we are going + // update xy + Q.xy += dQ.xy * stepCount; + // Q is a vector, so we are trying to get by with 1 division instead of 3. + csHitPoint = Q * (1.0 / k); + + return intersecting; +} + + +#endif // SCREEN_SPACE_RAYTRACE_INCLUDED diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/ScreenSpaceReflection/Resources/ScreenSpaceRaytrace.cginc.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/ScreenSpaceReflection/Resources/ScreenSpaceRaytrace.cginc.meta new file mode 100644 index 0000000..3c90b99 --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/ScreenSpaceReflection/Resources/ScreenSpaceRaytrace.cginc.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 6f70a4658ebf5f947abc302c6b49a6ba +timeCreated: 1449750676 +licenseType: Store +ShaderImporter: + defaultTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/ScreenSpaceReflection/Resources/ScreenSpaceReflection.shader b/IronToad_UnityProject/Assets/Standard Assets/Effects/ScreenSpaceReflection/Resources/ScreenSpaceReflection.shader new file mode 100644 index 0000000..13869ed --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/ScreenSpaceReflection/Resources/ScreenSpaceReflection.shader @@ -0,0 +1,949 @@ +/** +\author Michael Mara and Morgan McGuire, Casual Effects. 2015. +*/ +Shader "Hidden/ScreenSpaceReflection" +{ + Properties + { + _MainTex ("Base (RGB)", 2D) = "white" {} + } + + + CGINCLUDE + + #include "UnityCG.cginc" + #include "UnityPBSLighting.cginc" + #include "UnityStandardBRDF.cginc" + #include "UnityStandardUtils.cginc" + #include "ScreenSpaceRaytrace.cginc" + + float4 _ProjInfo; + float4x4 _WorldToCameraMatrix; + float4x4 _CameraToWorldMatrix; + float4x4 _ProjectToPixelMatrix; + float2 _ScreenSize; + float2 _ReflectionBufferSize; + float2 _InvScreenSize; + float3 _CameraClipInfo; + + sampler2D _CameraGBufferTexture0; + sampler2D _CameraGBufferTexture1; + sampler2D _CameraGBufferTexture2; + sampler2D _CameraGBufferTexture3; + sampler2D _CameraReflectionsTexture; + + float _CurrentMipLevel; + float _RayStepSize; + float _MaxRayTraceDistance; + float _LayerThickness; + float _FresnelFade; + float _FresnelFadePower; + float _ReflectionBlur; + + + sampler2D _MainTex; + + int _HalfResolution; + int _TreatBackfaceHitAsMiss; + int _AllowBackwardsRays; + + + // RG: SS Hitpoint of ray + // B: distance ray travelled, used for mip-selection in the final resolve + // A: confidence value + sampler2D _HitPointTexture; + sampler2D _FinalReflectionTexture; + + // RGB: camera-space normal (encoded in [0-1]) + // A: Roughness + sampler2D _NormalAndRoughnessTexture; + + float4 _MainTex_TexelSize; + + int _EnableRefine; + int _AdditiveReflection; + + float _ScreenEdgeFading; + + int _MaxSteps; + + int _BilateralUpsampling; + + float _MaxRoughness; + float _RoughnessFalloffRange; + float _SSRMultiplier; + + float _FadeDistance; + + int _TraceBehindObjects; + int _UseEdgeDetector; + int _HighlightSuppression; + + /** The height in pixels of a 1m object if viewed from 1m away. */ + float _PixelsPerMeterAtOneMeter; + + // For temporal filtering: + float4x4 _CurrentCameraToPreviousCamera; + sampler2D _PreviousReflectionTexture; + sampler2D _PreviousCSZBuffer; + float _TemporalAlpha; + int _UseTemporalConfidence; + + struct v2f + { + float4 pos : SV_POSITION; + float2 uv : TEXCOORD0; + float2 uv2 : TEXCOORD1; + }; + + v2f vert( appdata_img v ) + { + v2f o; + + o.pos = mul(UNITY_MATRIX_MVP, v.vertex); + o.uv = v.texcoord.xy; + o.uv2 = v.texcoord.xy; + + #if UNITY_UV_STARTS_AT_TOP + if (_MainTex_TexelSize.y < 0) + o.uv2.y = 1-o.uv2.y; + #endif + + return o; + } + + float2 mipToSize(int mip) + { + return floor(_ReflectionBufferSize * exp2(-mip)); + } + + float3 ReconstructCSPosition(float2 S, float z) + { + float linEyeZ = -LinearEyeDepth(z); + return float3(( (( S.xy * _MainTex_TexelSize.zw) ) * _ProjInfo.xy + _ProjInfo.zw) * linEyeZ, linEyeZ); + } + + /** Read the camera-space position of the point at screen-space pixel ssP */ + float3 GetPosition(float2 ssP) + { + float3 P; + + P.z = SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, ssP.xy); + + // Offset to pixel center + P = ReconstructCSPosition(float2(ssP) /*+ float2(0.5, 0.5)*/, P.z); + return P; + } + + float square(float x) + { + return x*x; + } + + float applyEdgeFade(float2 tsP, float fadeStrength) + { + float maxFade = 0.1; + + float2 itsP = float2(1.0, 1.0) - tsP; + float dist = min(min(itsP.x, itsP.y), min(tsP.x, tsP.x)); + float fade = dist / (maxFade*fadeStrength + 0.001); + fade = max(min(fade, 1.0), 0.0); + fade = pow(fade, 0.2); + + return fade; + } + + float3 csMirrorVector(float3 csPosition, float3 csN) + { + float3 csE = -normalize(csPosition.xyz); + float cos_o = dot(csN, csE); + float3 c_mi = normalize((csN * (2.0 * cos_o)) - csE); + + return c_mi; + } + + + float4 fragRaytrace(v2f i, int stepRate) + { + float2 ssP = i.uv2.xy; + float3 csPosition = GetPosition(ssP); + + float smoothness = tex2D(_CameraGBufferTexture1, ssP).a; + if (csPosition.z < -100.0 || smoothness == 0.0) + { + return float4(0.0,0.0,0.0,0.0); + } + + float3 wsNormal = tex2D(_CameraGBufferTexture2, ssP).rgb * 2.0 - 1.0; + + int2 ssC = int2(ssP * _ScreenSize); + + float3 csN = mul((float3x3)(_WorldToCameraMatrix), wsNormal); + float3 csRayDirection = csMirrorVector(csPosition, csN); + + if (_AllowBackwardsRays == 0 && csRayDirection.z > 0.0) + { + return float4(0.0, 0.0, 0.0, 0.0); + } + + float maxRayTraceDistance = _MaxRayTraceDistance; + float jitterFraction = 0.0f; + float layerThickness = _LayerThickness; + + int maxSteps = _MaxSteps; + + // Bump the ray more in world space as it gets farther away (and so each pixel covers more WS distance) + float rayBump = max(-0.01*csPosition.z, 0.001); + float2 hitPixel; + float3 csHitPoint; + float stepCount; + + bool wasHit = castDenseScreenSpaceRay + (csPosition + (csN) * rayBump, + csRayDirection, + _ProjectToPixelMatrix, + _ScreenSize, + _CameraClipInfo, + jitterFraction, + maxSteps, + layerThickness, + maxRayTraceDistance, + hitPixel, + stepRate, + _TraceBehindObjects == 1, + csHitPoint, + stepCount); + + float2 tsPResult = hitPixel / _ScreenSize; + + float rayDist = dot(csHitPoint - csPosition, csRayDirection); + float confidence = 0.0; + + if (wasHit) + { + confidence = square(1.0 - max(2.0*float(stepCount) / float(maxSteps) - 1.0, 0.0)); + confidence *= clamp(((_MaxRayTraceDistance - rayDist) / _FadeDistance), 0.0, 1.0); + + // Fake fresnel fade + float3 csE = -normalize(csPosition.xyz); + confidence *= max(0.0, lerp(pow(abs(dot(csRayDirection, -csE)), _FresnelFadePower), 1, 1.0 - _FresnelFade)); + + if (_TreatBackfaceHitAsMiss > 0) + { + float3 wsHitNormal = tex2Dlod(_CameraGBufferTexture2, float4(tsPResult, 0, 0)).rgb * 2.0 - 1.0; + float3 wsRayDirection = mul(_CameraToWorldMatrix, float4(csRayDirection, 0)).xyz; + + if (dot(wsHitNormal, wsRayDirection) > 0) + { + confidence = 0.0; + } + } + + } + + // Fade out reflections that hit near edge of screen, to prevent abrupt appearance/disappearance when object go off screen + // Fade out reflections that hit near edge of screen, + // to prevent abrupt appearance/disappearance when object go off screen + float vignette = applyEdgeFade(tsPResult, _ScreenEdgeFading); + confidence *= vignette; + confidence *= vignette; + + + return float4(tsPResult, rayDist, confidence); + } + + float4 fragComposite(v2f i) : SV_Target + { + // Pixel being shaded + float2 tsP = i.uv2.xy; + + // View space point being shaded + float3 C = GetPosition(tsP); + + // Final image before this pass + float4 gbuffer3 = tex2D(_MainTex, i.uv); + + float4 specEmission = float4(0.0,0.0,0.0,0.0); + float3 specColor = tex2D(_CameraGBufferTexture1, tsP).rgb; + + float roughness = 1.0-tex2D(_CameraGBufferTexture1, tsP).a; + + float4 reflectionTexel = tex2D(_FinalReflectionTexture, tsP); + + float4 gbuffer0 = tex2D(_CameraGBufferTexture0, tsP); + // Let core Unity functions do the dirty work of applying the BRDF + float3 baseColor = gbuffer0.rgb; + float occlusion = gbuffer0.a; + float oneMinusReflectivity; + baseColor = EnergyConservationBetweenDiffuseAndSpecular(baseColor, specColor, oneMinusReflectivity); + + float3 wsNormal = tex2D(_CameraGBufferTexture2, tsP).rgb * 2.0 - 1.0; + + float3 csEyeVec = normalize(C); + float3 eyeVec = mul(_CameraToWorldMatrix, float4(csEyeVec, 0)).xyz; + + float3 worldPos = mul(_CameraToWorldMatrix, float4(C, 1)).xyz; + + float cos_o = dot(wsNormal, eyeVec); + float3 w_mi = -normalize((wsNormal * (2.0 * cos_o)) - eyeVec); + + + float3 incomingRadiance = reflectionTexel.rgb; + + UnityLight light; + light.color = 0; + light.dir = 0; + light.ndotl = 0; + + UnityIndirect ind; + ind.diffuse = 0; + ind.specular = incomingRadiance; + + float3 ssrResult = UNITY_BRDF_PBS (0, specColor, oneMinusReflectivity, 1-roughness, wsNormal, -eyeVec, light, ind).rgb * _SSRMultiplier; + float confidence = reflectionTexel.a; + + specEmission.rgb = tex2D(_CameraReflectionsTexture, tsP).rgb; + float3 finalGlossyTerm; + + // Subtract out Unity's glossy result: (we're just applying the delta) + if (_AdditiveReflection == 0) + { + gbuffer3 -= specEmission; + // We may have blown out our dynamic range by adding then subtracting the reflection probes. + // As a half-measure to fix this, simply clamp to zero + gbuffer3 = max(gbuffer3, 0); + finalGlossyTerm = lerp(specEmission.rgb, ssrResult, saturate(confidence)); + } + else + { + finalGlossyTerm = ssrResult*saturate(confidence); + } + + finalGlossyTerm *= occlusion; + + // Additively blend the glossy GI result with the output buffer + return gbuffer3 + float4(finalGlossyTerm, 0); + } + + float roughnessWeight(float midpointRoughness, float tapRoughness) + { + return (1.0 - sqrt(sqrt(abs(midpointRoughness-tapRoughness)))); + } + + float normalWeight(float3 midpointNormal, float3 tapNormal) + { + return clamp(dot(midpointNormal, tapNormal), 0, 1); + } + + float highlightDecompression(float x) + { + return x / (1.0 - x); + } + + float3 highlightDecompression(float3 x) + { + return float3( + highlightDecompression(x.x), + highlightDecompression(x.y), + highlightDecompression(x.z)); + } + + float highlightCompression(float x) + { + return x / (1.0 + x); + } + + float3 highlightCompression(float3 x) + { + return float3( + highlightCompression(x.x), + highlightCompression(x.y), + highlightCompression(x.z)); + } + + float4 _Axis; + float4 fragGBlur(v2f i) : SV_Target + { + int radius = 4; + + // Pixel being shaded + float2 tsP = i.uv2.xy; + + float weightSum = 0.0; + float gaussWeights[5] = { 0.225, 0.150, 0.110, 0.075, 0.0525 };//{0.225, 0.150, 0.110, 0.075, 0.0525}; + float4 resultSum = float4(0.0, 0.0, 0.0, 0.0); + float4 unweightedResultSum = float4(0.0, 0.0, 0.0, 0.0); + float4 nAndRough = tex2D(_NormalAndRoughnessTexture, tsP); + float midpointRoughness = nAndRough.a; + float3 midpointNormal = nAndRough.rgb * 2 - 1; + + for (int i = -radius; i <= radius; ++i) + { + float4 temp; + float tapRoughness; + float3 tapNormal; + float2 tsTap = tsP + (_Axis.xy * _MainTex_TexelSize.xy * float2(i,i)*2.0); + + temp = tex2D(_MainTex, tsTap); + + float weight = temp.a * gaussWeights[abs(i)]; + // Bilateral filtering + // if (_ImproveCorners) + // { + nAndRough = tex2D(_NormalAndRoughnessTexture, tsTap); + tapRoughness = nAndRough.a; + tapNormal = nAndRough.rgb * 2 - 1; + weight *= normalWeight(midpointNormal, tapNormal); + // } + + weightSum += weight; + + if (_HighlightSuppression) + { + temp.rgb = highlightCompression(temp.rgb); + } + + unweightedResultSum += temp; + resultSum += temp*weight; + } + + if (weightSum > 0.01) + { + float invWeightSum = (1.0/weightSum); + // Adding the sqrt seems to decrease temporal flickering at the expense + // of having larger "halos" of fallback on rough surfaces + // Subject to change with testing. Sqrt around only half the expression is *intentional*. + float confidence = min(resultSum.a * sqrt(max(invWeightSum, 2.0)), 1.0); + float3 finalColor = resultSum.rgb * invWeightSum; + + if (_HighlightSuppression) + { + finalColor = highlightDecompression(finalColor); + } + + return float4(finalColor, confidence); + } + else + { + float3 finalColor = unweightedResultSum.rgb / (2 * radius + 1); + + if (_HighlightSuppression) + { + finalColor = highlightDecompression(finalColor); + } + + return float4(finalColor, 0.0); + } + } + + sampler2D _ReflectionTexture0; + sampler2D _ReflectionTexture1; + sampler2D _ReflectionTexture2; + sampler2D _ReflectionTexture3; + sampler2D _ReflectionTexture4; + + // Simulate mip maps, since we don't have NPOT mip-chains + float4 getReflectionValue(float2 tsP, int mip) + { + float4 coord = float4(tsP,0,0); + if (mip == 0) + { + return tex2Dlod(_ReflectionTexture0, coord); + } + else if (mip == 1) + { + return tex2Dlod(_ReflectionTexture1, coord); + } + else if (mip == 2) + { + return tex2Dlod(_ReflectionTexture2, coord); + } + else if (mip == 3) + { + return tex2Dlod(_ReflectionTexture3, coord); + } + else + { + return tex2Dlod(_ReflectionTexture4, coord); + } + } + + sampler2D _EdgeTexture0; + sampler2D _EdgeTexture1; + sampler2D _EdgeTexture2; + sampler2D _EdgeTexture3; + sampler2D _EdgeTexture4; + + // Simulate mip maps, since we don't have NPOT mip-chains + float4 getEdgeValue(float2 tsP, int mip) + { + float4 coord = float4(tsP + float2(1.0/(2 * mipToSize(mip))),0,0); + + if (mip == 0) + { + return tex2Dlod(_EdgeTexture0, coord); + } + else if (mip == 1) + { + return tex2Dlod(_EdgeTexture1, coord); + } + else if (mip == 2) + { + return tex2Dlod(_EdgeTexture2, coord); + } + else if (mip == 3) + { + return tex2Dlod(_EdgeTexture3, coord); + } + else + { + return tex2Dlod(_EdgeTexture4, coord); + } + } + + float2 centerPixel(float2 inputP) + { + return floor(inputP - float2(0.5,0.5)) + float2(0.5,0.5); + } + + float2 snapToTexelCenter(float2 inputP, float2 texSize, float2 texSizeInv) + { + return centerPixel(inputP * texSize) * texSizeInv; + } + + float4 bilateralUpsampleReflection(float2 tsP, int mip) + { + float2 smallTexSize = mipToSize(mip); + float2 smallPixelPos = tsP * smallTexSize; + float2 smallPixelPosi = centerPixel(smallPixelPos); + float2 smallTexSizeInv = 1.0 / smallTexSize; + + + float2 p0 = smallPixelPosi * smallTexSizeInv; + float2 p3 = (smallPixelPosi + float2(1.0, 1.0)) * smallTexSizeInv; + float2 p1 = float2(p3.x, p0.y); + float2 p2 = float2(p0.x, p3.y); + + float4 V0 = getReflectionValue(p0.xy, mip); + float4 V1 = getReflectionValue(p1.xy, mip); + float4 V2 = getReflectionValue(p2.xy, mip); + float4 V3 = getReflectionValue(p3.xy, mip); + + // Bilateral weights: + // Bilinear interpolation (filter distance) + float2 smallPixelPosf = smallPixelPos - smallPixelPosi; + float a0 = (1.0 - smallPixelPosf.x) * (1.0 - smallPixelPosf.y); + float a1 = smallPixelPosf.x * (1.0 - smallPixelPosf.y); + float a2 = (1.0 - smallPixelPosf.x) * smallPixelPosf.y; + float a3 = smallPixelPosf.x * smallPixelPosf.y; + + float2 fullTexSize = _ReflectionBufferSize; + float2 fullTexSizeInv = 1.0 / fullTexSize; + + float4 hiP0 = float4(snapToTexelCenter(p0, fullTexSize, fullTexSizeInv), 0,0); + float4 hiP3 = float4(snapToTexelCenter(p3, fullTexSize, fullTexSizeInv), 0,0); + float4 hiP1 = float4(snapToTexelCenter(p1, fullTexSize, fullTexSizeInv), 0,0); + float4 hiP2 = float4(snapToTexelCenter(p2, fullTexSize, fullTexSizeInv), 0,0); + + float4 tempCenter = tex2Dlod(_NormalAndRoughnessTexture, float4(tsP, 0, 0)); + float3 n = tempCenter.xyz * 2 - 1; + + float4 temp0 = tex2Dlod(_NormalAndRoughnessTexture, hiP0); + float4 temp1 = tex2Dlod(_NormalAndRoughnessTexture, hiP1); + float4 temp2 = tex2Dlod(_NormalAndRoughnessTexture, hiP2); + float4 temp3 = tex2Dlod(_NormalAndRoughnessTexture, hiP3); + + float3 n0 = temp0.xyz * 2 - 1; + float3 n1 = temp1.xyz * 2 - 1; + float3 n2 = temp2.xyz * 2 - 1; + float3 n3 = temp3.xyz * 2 - 1; + + a0 *= normalWeight(n, n0); + a1 *= normalWeight(n, n1); + a2 *= normalWeight(n, n2); + a3 *= normalWeight(n, n3); + + float r = tempCenter.a; + float r0 = temp0.a; + float r1 = temp1.a; + float r2 = temp2.a; + float r3 = temp3.a; + + a0 *= roughnessWeight(r, r0); + a1 *= roughnessWeight(r, r1); + a2 *= roughnessWeight(r, r2); + a3 *= roughnessWeight(r, r3); + + // Slightly offset from zero + a0 = max(a0, 0.001); + a1 = max(a1, 0.001); + a2 = max(a2, 0.001); + a3 = max(a3, 0.001); + + // Nearest neighbor + // a0 = a1 = a2 = a3 = 1.0; + + // Normalize the blending weights (weights were chosen so that + // the denominator can never be zero) + float norm = 1.0 / (a0 + a1 + a2 + a3); + + // Blend + float4 value = (V0 * a0 + V1 * a1 + V2 * a2 + V3 * a3) * norm; + //return V0; + return value; + } + + /** Explicit bilinear fetches; must be used if the reflection buffer is bound using point sampling */ + float4 bilinearUpsampleReflection(float2 tsP, int mip) + { + float2 smallTexSize = mipToSize(mip); + float2 smallPixelPos = tsP * smallTexSize; + float2 smallPixelPosi = centerPixel(smallPixelPos); + float2 smallTexSizeInv = 1.0 / smallTexSize; + + + float2 p0 = smallPixelPosi * smallTexSizeInv; + float2 p3 = (smallPixelPosi + float2(1.0, 1.0)) * smallTexSizeInv; + float2 p1 = float2(p3.x, p0.y); + float2 p2 = float2(p0.x, p3.y); + + float4 V0 = getReflectionValue(p0.xy, mip); + float4 V1 = getReflectionValue(p1.xy, mip); + float4 V2 = getReflectionValue(p2.xy, mip); + float4 V3 = getReflectionValue(p3.xy, mip); + + float a0 = 1.0; + float a1 = 1.0; + float a2 = 1.0; + float a3 = 1.0; + + // Bilateral weights: + // Bilinear interpolation (filter distance) + float2 smallPixelPosf = smallPixelPos - smallPixelPosi; + a0 = (1.0 - smallPixelPosf.x) * (1.0 - smallPixelPosf.y); + a1 = smallPixelPosf.x * (1.0 - smallPixelPosf.y); + a2 = (1.0 - smallPixelPosf.x) * smallPixelPosf.y; + a3 = smallPixelPosf.x * smallPixelPosf.y; + + // Blend + float4 value = (V0 * a0 + V1 * a1 + V2 * a2 + V3 * a3); + return value; + } + + // Unity's roughness is GGX roughness squared + float roughnessToBlinnPhongExponent(float roughness) + { + float r2 = roughness*roughness; + return 2.0f / r2*r2 - 2.0f; + } + + float glossyLobeSlope(float roughness) + { + return pow(roughness, 4.0/3.0); + } + + + // Empirically based on our filter: + // Mip | Pixels + // -------------- + // 0 | 1 no filter, so single pixel + // 1 | 17 2r + 1 filter applied once, grabbing from pixels r away in either direction (r=8, four samples times stride of 2) + // 2 | 50 2r + 1 filter applied on double size pixels, and each of those pixels had reached another r out to the side 2(2r + 1) + m_1 + // 3 | 118 4(2r + 1) + m_2 + // 4 | 254 8(2r + 1) + m_3 + // + // Approximated by pixels = 16*2^mip-15 + // rearranging we get mip = log_2((pixels + 15) / 16) + // + float filterFootprintInPixelsToMip(float footprint) + { + return log2((footprint + 15) / 16); + } + + float3 ansiGradient(float t) + { + //return float3(t, t, t); + return fmod(floor(t * float3(8.0, 4.0, 2.0)), 2.0); + } + + float4 fragCompositeSSR(v2f i) : SV_Target + { + // Pixel being shaded + float2 tsP = i.uv2.xy; + + float roughness = 1.0-tex2D(_CameraGBufferTexture1, tsP).a; + + float rayDistance = tex2D(_HitPointTexture, tsP).z; + + // Get the camera space position of the reflection hit + float3 csPosition = GetPosition(tsP); + float3 wsNormal = tex2D(_CameraGBufferTexture2, tsP).rgb * 2.0 - 1.0; + float3 csN = mul((float3x3)(_WorldToCameraMatrix), wsNormal); + float3 c_mi = csMirrorVector(csPosition, csN); + float3 csHitpoint = c_mi * rayDistance + csPosition; + + + float gatherFootprintInMeters = glossyLobeSlope(roughness) * rayDistance; + // We could add a term that incorporates the normal + // This approximation assumes reflections happen at a glancing angle + float filterFootprintInPixels = gatherFootprintInMeters * _PixelsPerMeterAtOneMeter / csHitpoint.z; + if (_HalfResolution == 1) + { + filterFootprintInPixels *= 0.5; + } + + float mip = filterFootprintInPixelsToMip(filterFootprintInPixels); + + float nonPhysicalMip = pow(roughness, 3.0 / 4.0) * UNITY_SPECCUBE_LOD_STEPS; + + if (_HalfResolution == 1) + { + nonPhysicalMip = nonPhysicalMip * 0.7; + } + + mip = max(0, min(4, mip)); + + float4 result = 0.; + + { + int mipMin = int(mip); + int mipMax = min(mipMin + 1, 4); + float mipLerp = mip-mipMin; + + if (_BilateralUpsampling == 1) + { + result = lerp(bilateralUpsampleReflection(tsP, mipMin), bilateralUpsampleReflection(tsP, mipMax), mipLerp); + } + else + { + float4 minResult = getReflectionValue(tsP, mipMin); + float4 maxResult = getReflectionValue(tsP, mipMax); + result = lerp(minResult, maxResult, mipLerp); + result.a = min(minResult.a, maxResult.a); + } + } + + result.a = min(result.a, 1.0); + float vignette = applyEdgeFade(tsP, _ScreenEdgeFading); + result.a *= vignette; + + + // THIS MIGHT BE SLIGHTLY WRONG, TRY STEP() + float alphaModifier = 1.0 - clamp(roughness * .3, 0., 1.); + result.a *= alphaModifier; + return result; + } + + int _LastMip; + + float4 fragMin(v2f i) : SV_Target + { + float2 tsP = i.uv2.xy; + float2 lastTexSize = mipToSize(_LastMip); + float2 lastTexSizeInv = 1.0 / lastTexSize; + float2 p00 = snapToTexelCenter(tsP, lastTexSize, lastTexSizeInv); + float2 p11 = p00 + lastTexSizeInv; + + return min( + min(tex2D(_MainTex, p00), tex2D(_MainTex, p11)), + min(tex2D(_MainTex, float2(p00.x, p11.y)), tex2D(_MainTex, float2(p11.x, p00.y))) + ); + } + + float4 fragResolveHitPoints(v2f i) : SV_Target + { + float2 tsP = i.uv2.xy; + float4 temp = tex2D(_HitPointTexture, tsP); + float2 hitPoint = temp.xy; + float confidence = temp.w; + float3 colorResult = confidence > 0.0 ? tex2D(_MainTex, hitPoint).rgb : tex2D(_CameraReflectionsTexture, tsP).rgb; + + #ifdef UNITY_COMPILER_HLSL + /*if (any(isnan(colorResult))) + colorResult = float3(0.0, 0.0, 0.0); + + // As of 11/29/2015, on Unity 5.3 on a Windows 8.1 computer with a NVIDIA GeForce 980, + // with driver 347.62, the above check does not actually work to get rid of NaNs! + // So we add this "redundant" check. + if (!all(isfinite(colorResult))) + colorResult = float3(0.0, 0.0, 0.0);*/ + #endif + return float4(colorResult, confidence); + } + + float4 fragBilatKeyPack(v2f i) : SV_Target + { + float2 tsP = i.uv2.xy; + float3 csN = tex2D(_CameraGBufferTexture2, tsP).xyz; + float roughness = tex2D(_CameraGBufferTexture1, tsP).a; + return float4(csN, roughness); + } + + float4 fragDepthToCSZ(v2f i) : SV_Target + { + float depth = SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, i.uv2.xy); + return float4(-LinearEyeDepth(depth), 0.0, 0.0, 0.0); + } + + static const int NUM_POISSON_TAPS = 12; + // Same as used in CameraMotionBlur.shader + static const float2 poissonSamples[NUM_POISSON_TAPS] = + { + float2(-0.326212,-0.40581), + float2(-0.840144,-0.07358), + float2(-0.695914,0.457137), + float2(-0.203345,0.620716), + float2(0.96234,-0.194983), + float2(0.473434,-0.480026), + float2(0.519456,0.767022), + float2(0.185461,-0.893124), + float2(0.507431,0.064425), + float2(0.89642,0.412458), + float2(-0.32194,-0.932615), + float2(-0.791559,-0.59771) + }; + + float4 fragFilterSharpReflections(v2f i) : SV_Target + { + // Could improve perf by not computing blur when we won't be sampling the highest level anyways + float2 tsP = i.uv2.xy; + float4 sum = 0.0; + float sampleRadius = _MainTex_TexelSize.xy * _ReflectionBlur; + + for (int i = 0; i < NUM_POISSON_TAPS; i++) + { + float2 p = tsP + poissonSamples[i] * sampleRadius; + + float4 tap = tex2D(_MainTex, p); + if (_HighlightSuppression) + { + tap.rgb = highlightCompression(tap.rgb); + } + + sum += tap; + } + + float4 result = sum / float(NUM_POISSON_TAPS); + + if (_HighlightSuppression) + { + result.rgb = highlightDecompression(result.rgb); + } + + return result; + } + + ENDCG + + SubShader + { + ZTest Always Cull Off ZWrite Off + + // 0: Raytrace + Pass + { + CGPROGRAM + #pragma exclude_renderers gles xbox360 ps3 + #pragma vertex vert + #pragma fragment fragRaytrace1 + #pragma target 3.0 + + float4 fragRaytrace1(v2f i) : SV_Target + { + return fragRaytrace(i, _RayStepSize); + } + ENDCG + } + + // 1: Composite + Pass + { + CGPROGRAM + #pragma exclude_renderers gles xbox360 ps3 + #pragma vertex vert + #pragma fragment fragComposite + #pragma target 3.0 + ENDCG + } + + // 2: GBlur + Pass + { + CGPROGRAM + #pragma exclude_renderers gles xbox360 ps3 + #pragma vertex vert + #pragma fragment fragGBlur + #pragma target 3.0 + ENDCG + } + + // 3: CompositeSSR + Pass + { + CGPROGRAM + #pragma exclude_renderers gles xbox360 ps3 + #pragma vertex vert + #pragma fragment fragCompositeSSR + #pragma target 3.0 + ENDCG + } + + // 4: Min mip generation + Pass + { + CGPROGRAM + #pragma exclude_renderers gles xbox360 ps3 + #pragma vertex vert + #pragma fragment fragMin + #pragma target 3.0 + ENDCG + } + + // 5: Hit point texture to reflection buffer + Pass + { + CGPROGRAM + #pragma exclude_renderers gles xbox360 ps3 + #pragma vertex vert + #pragma fragment fragResolveHitPoints + #pragma target 3.0 + ENDCG + } + + // 6: Pack Bilateral Filter Keys in single buffer + Pass + { + CGPROGRAM + #pragma exclude_renderers gles xbox360 ps3 + #pragma vertex vert + #pragma fragment fragBilatKeyPack + #pragma target 3.0 + ENDCG + } + + // 7: Blit depth information as camera space Z + Pass + { + CGPROGRAM + #pragma exclude_renderers gles xbox360 ps3 + #pragma vertex vert + #pragma fragment fragDepthToCSZ + #pragma target 3.0 + ENDCG + } + + // 8: Filter the highest quality reflection buffer + Pass + { + CGPROGRAM + #pragma exclude_renderers gles xbox360 ps3 + #pragma vertex vert + #pragma fragment fragFilterSharpReflections + #pragma target 3.0 + ENDCG + } + + } + + Fallback "Diffuse" +} diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/ScreenSpaceReflection/Resources/ScreenSpaceReflection.shader.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/ScreenSpaceReflection/Resources/ScreenSpaceReflection.shader.meta new file mode 100644 index 0000000..170b098 --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/ScreenSpaceReflection/Resources/ScreenSpaceReflection.shader.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 7e2fcc83af19e744787647ec0ac5d42c +timeCreated: 1449750821 +licenseType: Store +ShaderImporter: + defaultTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/ScreenSpaceReflection/ScreenSpaceReflection.cs b/IronToad_UnityProject/Assets/Standard Assets/Effects/ScreenSpaceReflection/ScreenSpaceReflection.cs new file mode 100644 index 0000000..f1ea41c --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/ScreenSpaceReflection/ScreenSpaceReflection.cs @@ -0,0 +1,424 @@ +using System; +using UnityEngine; + +using UnityEngine.Rendering; + +namespace UnityStandardAssets.CinematicEffects +{ + [ExecuteInEditMode] +#if UNITY_5_4_OR_NEWER + [ImageEffectAllowedInSceneView] +#endif + [RequireComponent(typeof(Camera))] + [AddComponentMenu("Cinematic Image Effects/Screen Space Reflections")] + public class ScreenSpaceReflection : MonoBehaviour + { + public enum SSRResolution + { + High = 0, + Low = 2 + } + + public enum SSRReflectionBlendType + { + PhysicallyBased, + Additive + } + + [Serializable] + public struct SSRSettings + { + [AttributeUsage(AttributeTargets.Field)] + public class LayoutAttribute : PropertyAttribute + { + } + + [Layout] + public ReflectionSettings reflectionSettings; + + [Layout] + public IntensitySettings intensitySettings; + + [Layout] + public ScreenEdgeMask screenEdgeMask; + + private static readonly SSRSettings s_Default = new SSRSettings + { + reflectionSettings = new ReflectionSettings + { + blendType = SSRReflectionBlendType.PhysicallyBased, + reflectionQuality = SSRResolution.High, + maxDistance = 100.0f, + iterationCount = 256, + stepSize = 3, + widthModifier = 0.5f, + reflectionBlur = 1.0f, + reflectBackfaces = true + }, + + intensitySettings = new IntensitySettings + { + reflectionMultiplier = 1.0f, + fadeDistance = 100.0f, + + fresnelFade = 1.0f, + fresnelFadePower = 1.0f, + }, + + screenEdgeMask = new ScreenEdgeMask + { + intensity = 0.03f + } + }; + + public static SSRSettings defaultSettings + { + get + { + return s_Default; + } + } + } + + [Serializable] + public struct IntensitySettings + { + [Tooltip("Nonphysical multiplier for the SSR reflections. 1.0 is physically based.")] + [Range(0.0f, 2.0f)] + public float reflectionMultiplier; + + [Tooltip("How far away from the maxDistance to begin fading SSR.")] + [Range(0.0f, 1000.0f)] + public float fadeDistance; + + [Tooltip("Amplify Fresnel fade out. Increase if floor reflections look good close to the surface and bad farther 'under' the floor.")] + [Range(0.0f, 1.0f)] + public float fresnelFade; + + [Tooltip("Higher values correspond to a faster Fresnel fade as the reflection changes from the grazing angle.")] + [Range(0.1f, 10.0f)] + public float fresnelFadePower; + } + + [Serializable] + public struct ReflectionSettings + { + // When enabled, we just add our reflections on top of the existing ones. This is physically incorrect, but several + // popular demos and games have taken this approach, and it does hide some artifacts. + [Tooltip("How the reflections are blended into the render.")] + public SSRReflectionBlendType blendType; + + [Tooltip("Half resolution SSRR is much faster, but less accurate.")] + public SSRResolution reflectionQuality; + + [Tooltip("Maximum reflection distance in world units.")] + [Range(0.1f, 300.0f)] + public float maxDistance; + + /// REFLECTIONS + [Tooltip("Max raytracing length.")] + [Range(16, 1024)] + public int iterationCount; + + [Tooltip("Log base 2 of ray tracing coarse step size. Higher traces farther, lower gives better quality silhouettes.")] + [Range(1, 16)] + public int stepSize; + + [Tooltip("Typical thickness of columns, walls, furniture, and other objects that reflection rays might pass behind.")] + [Range(0.01f, 10.0f)] + public float widthModifier; + + [Tooltip("Blurriness of reflections.")] + [Range(0.1f, 8.0f)] + public float reflectionBlur; + + [Tooltip("Enable for a performance gain in scenes where most glossy objects are horizontal, like floors, water, and tables. Leave on for scenes with glossy vertical objects.")] + public bool reflectBackfaces; + } + + [Serializable] + public struct ScreenEdgeMask + { + [Tooltip("Higher = fade out SSRR near the edge of the screen so that reflections don't pop under camera motion.")] + [Range(0.0f, 1.0f)] + public float intensity; + } + + + [SerializeField] + public SSRSettings settings = SSRSettings.defaultSettings; + + ///////////// Unexposed Variables ////////////////// + + [Tooltip("Enable to limit the effect a few bright pixels can have on rougher surfaces")] + private bool highlightSuppression = false; + + [Tooltip("Enable to allow rays to pass behind objects. This can lead to more screen-space reflections, but the reflections are more likely to be wrong.")] + private bool traceBehindObjects = true; + + [Tooltip("Enable to force more surfaces to use reflection probes if you see streaks on the sides of objects or bad reflections of their backs.")] + private bool treatBackfaceHitAsMiss = false; + + [Tooltip("Drastically improves reflection reconstruction quality at the expense of some performance.")] + private bool bilateralUpsample = true; + + ///////////// Unexposed Variables ////////////////// + + [SerializeField] + private Shader m_Shader; + public Shader shader + { + get + { + if (m_Shader == null) + m_Shader = Shader.Find("Hidden/ScreenSpaceReflection"); + + return m_Shader; + } + } + + private Material m_Material; + public Material material + { + get + { + if (m_Material == null) + m_Material = ImageEffectHelper.CheckShaderAndCreateMaterial(shader); + + return m_Material; + } + } + + private Camera m_Camera; + public Camera camera_ + { + get + { + if (m_Camera == null) + m_Camera = GetComponent(); + + return m_Camera; + } + } + + private CommandBuffer m_CommandBuffer; + + private static int kNormalAndRoughnessTexture; + private static int kHitPointTexture; + private static int[] kReflectionTextures; + private static int kFilteredReflections; + private static int kBlurTexture; + private static int kFinalReflectionTexture; + private static int kTempTexture; + + // Shader pass indices used by the effect + private enum PassIndex + { + RayTraceStep = 0, + CompositeFinal = 1, + Blur = 2, + CompositeSSR = 3, + MinMipGeneration = 4, + HitPointToReflections = 5, + BilateralKeyPack = 6, + BlitDepthAsCSZ = 7, + PoissonBlur = 8, + } + + private void OnEnable() + { + if (!ImageEffectHelper.IsSupported(shader, false, true, this)) + { + enabled = false; + return; + } + + camera_.depthTextureMode |= DepthTextureMode.Depth; + + kReflectionTextures = new int[5]; + + kNormalAndRoughnessTexture = Shader.PropertyToID("_NormalAndRoughnessTexture"); + kHitPointTexture = Shader.PropertyToID("_HitPointTexture"); + kReflectionTextures[0] = Shader.PropertyToID("_ReflectionTexture0"); + kReflectionTextures[1] = Shader.PropertyToID("_ReflectionTexture1"); + kReflectionTextures[2] = Shader.PropertyToID("_ReflectionTexture2"); + kReflectionTextures[3] = Shader.PropertyToID("_ReflectionTexture3"); + kReflectionTextures[4] = Shader.PropertyToID("_ReflectionTexture4"); + kBlurTexture = Shader.PropertyToID("_BlurTexture"); + kFilteredReflections = Shader.PropertyToID("_FilteredReflections"); + kFinalReflectionTexture = Shader.PropertyToID("_FinalReflectionTexture"); + kTempTexture = Shader.PropertyToID("_TempTexture"); + } + + void OnDisable() + { + if (m_Material) + DestroyImmediate(m_Material); + + m_Material = null; + + if (camera_ != null) + { + if (m_CommandBuffer != null) + { + camera_.RemoveCommandBuffer(CameraEvent.AfterFinalPass, m_CommandBuffer); + } + + m_CommandBuffer = null; + } + } + +#if UNITY_EDITOR + void OnValidate() + { + if (camera_ != null) + { + if (m_CommandBuffer != null) + { + camera_.RemoveCommandBuffer(CameraEvent.AfterFinalPass, m_CommandBuffer); + } + + m_CommandBuffer = null; + } + } +#endif + + // [ImageEffectOpaque] + public void OnPreRender() + { + if (material == null) + { + return; + } + else if (Camera.current.actualRenderingPath != RenderingPath.DeferredShading) + { + return; + } + + int downsampleAmount = (settings.reflectionSettings.reflectionQuality == SSRResolution.High) ? 1 : 2; + + var rtW = camera_.pixelWidth / downsampleAmount; + var rtH = camera_.pixelHeight / downsampleAmount; + + float sWidth = camera_.pixelWidth; + float sHeight = camera_.pixelHeight; + + float sx = sWidth / 2.0f; + float sy = sHeight / 2.0f; + + const int maxMip = 5; + + RenderTextureFormat intermediateFormat = camera_.hdr ? RenderTextureFormat.ARGBHalf : RenderTextureFormat.ARGB32; + + material.SetInt("_RayStepSize", settings.reflectionSettings.stepSize); + material.SetInt("_AdditiveReflection", settings.reflectionSettings.blendType == SSRReflectionBlendType.Additive ? 1 : 0); + material.SetInt("_BilateralUpsampling", bilateralUpsample ? 1 : 0); + material.SetInt("_TreatBackfaceHitAsMiss", treatBackfaceHitAsMiss ? 1 : 0); + material.SetInt("_AllowBackwardsRays", settings.reflectionSettings.reflectBackfaces ? 1 : 0); + material.SetInt("_TraceBehindObjects", traceBehindObjects ? 1 : 0); + material.SetInt("_MaxSteps", settings.reflectionSettings.iterationCount); + material.SetInt("_FullResolutionFiltering", 0); + material.SetInt("_HalfResolution", (settings.reflectionSettings.reflectionQuality != SSRResolution.High) ? 1 : 0); + material.SetInt("_HighlightSuppression", highlightSuppression ? 1 : 0); + + /** The height in pixels of a 1m object if viewed from 1m away. */ + float pixelsPerMeterAtOneMeter = sWidth / (-2.0f * (float)(Math.Tan(camera_.fieldOfView / 180.0 * Math.PI * 0.5))); + + material.SetFloat("_PixelsPerMeterAtOneMeter", pixelsPerMeterAtOneMeter); + material.SetFloat("_ScreenEdgeFading", settings.screenEdgeMask.intensity); + material.SetFloat("_ReflectionBlur", settings.reflectionSettings.reflectionBlur); + material.SetFloat("_MaxRayTraceDistance", settings.reflectionSettings.maxDistance); + material.SetFloat("_FadeDistance", settings.intensitySettings.fadeDistance); + material.SetFloat("_LayerThickness", settings.reflectionSettings.widthModifier); + material.SetFloat("_SSRMultiplier", settings.intensitySettings.reflectionMultiplier); + material.SetFloat("_FresnelFade", settings.intensitySettings.fresnelFade); + material.SetFloat("_FresnelFadePower", settings.intensitySettings.fresnelFadePower); + + Matrix4x4 P = camera_.projectionMatrix; + Vector4 projInfo = new Vector4 + ((-2.0f / (sWidth * P[0])), + (-2.0f / (sHeight * P[5])), + ((1.0f - P[2]) / P[0]), + ((1.0f + P[6]) / P[5])); + + Vector3 cameraClipInfo = (float.IsPositiveInfinity(camera_.farClipPlane)) ? + new Vector3(camera_.nearClipPlane, -1.0f, 1.0f) : + new Vector3(camera_.nearClipPlane * camera_.farClipPlane, camera_.nearClipPlane - camera_.farClipPlane, camera_.farClipPlane); + + material.SetVector("_ReflectionBufferSize", new Vector2(rtW, rtH)); + material.SetVector("_ScreenSize", new Vector2(sWidth, sHeight)); + material.SetVector("_InvScreenSize", new Vector2((float)(1.0f / sWidth), (float)(1.0f / sHeight))); + material.SetVector("_ProjInfo", projInfo); // used for unprojection + + material.SetVector("_CameraClipInfo", cameraClipInfo); + + Matrix4x4 warpToScreenSpaceMatrix = new Matrix4x4(); + warpToScreenSpaceMatrix.SetRow(0, new Vector4(sx, 0.0f, 0.0f, sx)); + warpToScreenSpaceMatrix.SetRow(1, new Vector4(0.0f, sy, 0.0f, sy)); + warpToScreenSpaceMatrix.SetRow(2, new Vector4(0.0f, 0.0f, 1.0f, 0.0f)); + warpToScreenSpaceMatrix.SetRow(3, new Vector4(0.0f, 0.0f, 0.0f, 1.0f)); + + Matrix4x4 projectToPixelMatrix = warpToScreenSpaceMatrix * P; + + material.SetMatrix("_ProjectToPixelMatrix", projectToPixelMatrix); + material.SetMatrix("_WorldToCameraMatrix", camera_.worldToCameraMatrix); + material.SetMatrix("_CameraToWorldMatrix", camera_.worldToCameraMatrix.inverse); + + if (m_CommandBuffer == null) + { + m_CommandBuffer = new CommandBuffer(); + m_CommandBuffer.name = "Screen Space Reflections"; + + // RGB: Normals, A: Roughness. + // Has the nice benefit of allowing us to control the filtering mode as well. + m_CommandBuffer.GetTemporaryRT(kNormalAndRoughnessTexture, -1, -1, 0, FilterMode.Point, RenderTextureFormat.ARGB32, RenderTextureReadWrite.Linear); + + m_CommandBuffer.GetTemporaryRT(kHitPointTexture, rtW, rtH, 0, FilterMode.Bilinear, RenderTextureFormat.ARGBHalf, RenderTextureReadWrite.Linear); + + for (int i = 0; i < maxMip; ++i) + { + // We explicitly interpolate during bilateral upsampling. + m_CommandBuffer.GetTemporaryRT(kReflectionTextures[i], rtW >> i, rtH >> i, 0, FilterMode.Bilinear, intermediateFormat); + } + + m_CommandBuffer.GetTemporaryRT(kFilteredReflections, rtW, rtH, 0, bilateralUpsample ? FilterMode.Point : FilterMode.Bilinear, intermediateFormat); + m_CommandBuffer.GetTemporaryRT(kFinalReflectionTexture, rtW, rtH, 0, FilterMode.Point, intermediateFormat); + + m_CommandBuffer.Blit(BuiltinRenderTextureType.CameraTarget, kNormalAndRoughnessTexture, material, (int)PassIndex.BilateralKeyPack); + m_CommandBuffer.Blit(BuiltinRenderTextureType.CameraTarget, kHitPointTexture, material, (int)PassIndex.RayTraceStep); + m_CommandBuffer.Blit(BuiltinRenderTextureType.CameraTarget, kFilteredReflections, material, (int)PassIndex.HitPointToReflections); + m_CommandBuffer.Blit(kFilteredReflections, kReflectionTextures[0], material, (int)PassIndex.PoissonBlur); + + for (int i = 1; i < maxMip; ++i) + { + int inputTex = kReflectionTextures[i - 1]; + + int lowMip = i; + + m_CommandBuffer.GetTemporaryRT(kBlurTexture, rtW >> lowMip, rtH >> lowMip, 0, FilterMode.Bilinear, intermediateFormat); + m_CommandBuffer.SetGlobalVector("_Axis", new Vector4(1.0f, 0.0f, 0.0f, 0.0f)); + m_CommandBuffer.SetGlobalFloat("_CurrentMipLevel", i - 1.0f); + + m_CommandBuffer.Blit(inputTex, kBlurTexture, material, (int)PassIndex.Blur); + + m_CommandBuffer.SetGlobalVector("_Axis", new Vector4(0.0f, 1.0f, 0.0f, 0.0f)); + + inputTex = kReflectionTextures[i]; + m_CommandBuffer.Blit(kBlurTexture, inputTex, material, (int)PassIndex.Blur); + m_CommandBuffer.ReleaseTemporaryRT(kBlurTexture); + } + + m_CommandBuffer.Blit(kReflectionTextures[0], kFinalReflectionTexture, material, (int)PassIndex.CompositeSSR); + + m_CommandBuffer.GetTemporaryRT(kTempTexture, camera_.pixelWidth, camera_.pixelHeight, 0, FilterMode.Bilinear, intermediateFormat); + + m_CommandBuffer.Blit(BuiltinRenderTextureType.CameraTarget, kTempTexture, material, (int)PassIndex.CompositeFinal); + m_CommandBuffer.Blit(kTempTexture, BuiltinRenderTextureType.CameraTarget); + + + m_CommandBuffer.ReleaseTemporaryRT(kTempTexture); + camera_.AddCommandBuffer(CameraEvent.AfterFinalPass, m_CommandBuffer); + } + } + } +} diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/ScreenSpaceReflection/ScreenSpaceReflection.cs.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/ScreenSpaceReflection/ScreenSpaceReflection.cs.meta new file mode 100644 index 0000000..fc99e3a --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/ScreenSpaceReflection/ScreenSpaceReflection.cs.meta @@ -0,0 +1,13 @@ +fileFormatVersion: 2 +guid: da3ff4a1bef2e8d47a1dfb734aa54de1 +timeCreated: 1433488439 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: + - ssrShader: {fileID: 4800000, guid: 7e2fcc83af19e744787647ec0ac5d42c, type: 3} + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/TonemappingColorGrading.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/TonemappingColorGrading.meta new file mode 100644 index 0000000..ccbb7eb --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/TonemappingColorGrading.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 33083b2f3c4953846890c256af8cc606 +folderAsset: yes +timeCreated: 1435676891 +licenseType: Store +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/TonemappingColorGrading/Editor.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/TonemappingColorGrading/Editor.meta new file mode 100644 index 0000000..f54837b --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/TonemappingColorGrading/Editor.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: a232fdc401b30b549b2ac3a54d76f6cc +folderAsset: yes +timeCreated: 1448359112 +licenseType: Store +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/TonemappingColorGrading/Editor/TonemappingColorGradingEditor.cs b/IronToad_UnityProject/Assets/Standard Assets/Effects/TonemappingColorGrading/Editor/TonemappingColorGradingEditor.cs new file mode 100644 index 0000000..8d30a3a --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/TonemappingColorGrading/Editor/TonemappingColorGradingEditor.cs @@ -0,0 +1,736 @@ +namespace UnityStandardAssets.CinematicEffects +{ + using UnityEngine; + using UnityEditor; + using UnityEditorInternal; + using System.Reflection; + using System.Collections.Generic; + using System.Linq; + + [CanEditMultipleObjects, CustomEditor(typeof(TonemappingColorGrading))] + public class TonemappingColorGradingEditor : Editor + { + #region Property drawers + [CustomPropertyDrawer(typeof(TonemappingColorGrading.ColorWheelGroup))] + private class ColorWheelGroupDrawer : PropertyDrawer + { + int m_RenderSizePerWheel; + int m_NumberOfWheels; + + public override float GetPropertyHeight(SerializedProperty property, GUIContent label) + { + var wheelAttribute = (TonemappingColorGrading.ColorWheelGroup)attribute; + property.isExpanded = true; + + m_NumberOfWheels = property.CountInProperty() - 1; + if (m_NumberOfWheels == 0) + return 0f; + + m_RenderSizePerWheel = Mathf.FloorToInt((EditorGUIUtility.currentViewWidth) / m_NumberOfWheels) - 30; + m_RenderSizePerWheel = Mathf.Clamp(m_RenderSizePerWheel, wheelAttribute.minSizePerWheel, wheelAttribute.maxSizePerWheel); + m_RenderSizePerWheel = Mathf.FloorToInt(pixelRatio * m_RenderSizePerWheel); + return ColorWheel.GetColorWheelHeight(m_RenderSizePerWheel); + } + + public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) + { + if (m_NumberOfWheels == 0) + return; + + var width = position.width; + Rect newPosition = new Rect(position.x, position.y, width / m_NumberOfWheels, position.height); + + foreach (SerializedProperty prop in property) + { + if (prop.propertyType == SerializedPropertyType.Color) + prop.colorValue = ColorWheel.DoGUI(newPosition, prop.displayName, prop.colorValue, m_RenderSizePerWheel); + + newPosition.x += width / m_NumberOfWheels; + } + } + } + + [CustomPropertyDrawer(typeof(TonemappingColorGrading.IndentedGroup))] + private class IndentedGroupDrawer : PropertyDrawer + { + public override float GetPropertyHeight(SerializedProperty property, GUIContent label) + { + return 0f; + } + + public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) + { + EditorGUILayout.LabelField(label, EditorStyles.boldLabel); + + EditorGUI.indentLevel++; + + foreach (SerializedProperty prop in property) + EditorGUILayout.PropertyField(prop); + + EditorGUI.indentLevel--; + } + } + + [CustomPropertyDrawer(typeof(TonemappingColorGrading.ChannelMixer))] + private class ChannelMixerDrawer : PropertyDrawer + { + public override float GetPropertyHeight(SerializedProperty property, GUIContent label) + { + return 0f; + } + + public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) + { + // TODO: Hardcoded variable names, rewrite this function + if (property.type != "ChannelMixerSettings") + return; + + SerializedProperty currentChannel = property.FindPropertyRelative("currentChannel"); + int intCurrentChannel = currentChannel.intValue; + + EditorGUILayout.LabelField(label, EditorStyles.boldLabel); + + EditorGUI.indentLevel++; + + EditorGUILayout.BeginHorizontal(); + { + EditorGUILayout.PrefixLabel("Channel"); + if (GUILayout.Toggle(intCurrentChannel == 0, "Red", EditorStyles.miniButtonLeft)) intCurrentChannel = 0; + if (GUILayout.Toggle(intCurrentChannel == 1, "Green", EditorStyles.miniButtonMid)) intCurrentChannel = 1; + if (GUILayout.Toggle(intCurrentChannel == 2, "Blue", EditorStyles.miniButtonRight)) intCurrentChannel = 2; + } + EditorGUILayout.EndHorizontal(); + + SerializedProperty serializedChannel = property.FindPropertyRelative("channels").GetArrayElementAtIndex(intCurrentChannel); + currentChannel.intValue = intCurrentChannel; + + Vector3 v = serializedChannel.vector3Value; + v.x = EditorGUILayout.Slider("Red", v.x, -2f, 2f); + v.y = EditorGUILayout.Slider("Green", v.y, -2f, 2f); + v.z = EditorGUILayout.Slider("Blue", v.z, -2f, 2f); + serializedChannel.vector3Value = v; + + EditorGUI.indentLevel--; + } + } + + [CustomPropertyDrawer(typeof(TonemappingColorGrading.Curve))] + private class CurveDrawer : PropertyDrawer + { + public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) + { + TonemappingColorGrading.Curve attribute = (TonemappingColorGrading.Curve)base.attribute; + + if (property.propertyType != SerializedPropertyType.AnimationCurve) + { + EditorGUI.LabelField(position, label.text, "Use ClampCurve with an AnimationCurve."); + return; + } + + property.animationCurveValue = EditorGUI.CurveField(position, label, property.animationCurveValue, attribute.color, new Rect(0f, 0f, 1f, 1f)); + } + } + #endregion + + #region Styling + private static Styles s_Styles; + private class Styles + { + public GUIStyle thumb2D = "ColorPicker2DThumb"; + public Vector2 thumb2DSize; + + internal Styles() + { + thumb2DSize = new Vector2( + !Mathf.Approximately(thumb2D.fixedWidth, 0f) ? thumb2D.fixedWidth : thumb2D.padding.horizontal, + !Mathf.Approximately(thumb2D.fixedHeight, 0f) ? thumb2D.fixedHeight : thumb2D.padding.vertical + ); + } + } + + public static readonly Color masterCurveColor = new Color(1f, 1f, 1f, 2f); + public static readonly Color redCurveColor = new Color(1f, 0f, 0f, 2f); + public static readonly Color greenCurveColor = new Color(0f, 1f, 0f, 2f); + public static readonly Color blueCurveColor = new Color(0f, 1f, 1f, 2f); + #endregion + + private TonemappingColorGrading concreteTarget + { + get { return target as TonemappingColorGrading; } + } + + private static float pixelRatio + { + get + { + #if !(UNITY_3 || UNITY_4 || UNITY_5_0 || UNITY_5_1 || UNITY_5_2 || UNITY_5_3) + return EditorGUIUtility.pixelsPerPoint; + #else + return 1f; + #endif + } + } + + private bool isHistogramSupported + { + get + { + return concreteTarget.histogramComputeShader != null + && ImageEffectHelper.supportsDX11 + && concreteTarget.histogramShader != null + && concreteTarget.histogramShader.isSupported; + } + } + + private enum HistogramMode + { + Red = 0, + Green = 1, + Blue = 2, + Luminance = 3, + RGB, + } + + private HistogramMode m_HistogramMode = HistogramMode.RGB; + private Rect m_HistogramRect; + private Material m_HistogramMaterial; + private ComputeBuffer m_HistogramBuffer; + private RenderTexture m_HistogramTexture; + + // settings group + private Dictionary> m_GroupFields = new Dictionary>(); + + private void PopulateMap(FieldInfo group) + { + var searchPath = group.Name + "."; + foreach (var setting in group.FieldType.GetFields(BindingFlags.Instance | BindingFlags.Public)) + { + List settingsGroup; + if (!m_GroupFields.TryGetValue(group, out settingsGroup)) + { + settingsGroup = new List(); + m_GroupFields[group] = settingsGroup; + } + + var property = serializedObject.FindProperty(searchPath + setting.Name); + if (property != null) + settingsGroup.Add(property); + } + } + + private void OnEnable() + { + var settingsGroups = typeof(TonemappingColorGrading).GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance).Where(x => x.GetCustomAttributes(typeof(TonemappingColorGrading.SettingsGroup), false).Any()); + + foreach (var settingGroup in settingsGroups) + PopulateMap(settingGroup); + + concreteTarget.onFrameEndEditorOnly = OnFrameEnd; + } + + private void OnDisable() + { + concreteTarget.onFrameEndEditorOnly = null; + + if (m_HistogramMaterial != null) + DestroyImmediate(m_HistogramMaterial); + + if (m_HistogramTexture != null) + DestroyImmediate(m_HistogramTexture); + + if (m_HistogramBuffer != null) + m_HistogramBuffer.Release(); + } + + private void SetLUTImportSettings(TextureImporter importer) + { + importer.textureType = TextureImporterType.Default; + importer.anisoLevel = 0; + importer.mipmapEnabled = false; + importer.linearTexture = true; + importer.textureFormat = TextureImporterFormat.RGB24; + importer.SaveAndReimport(); + } + + private void DrawFields() + { + foreach (var group in m_GroupFields) + { + var enabledField = group.Value.FirstOrDefault(x => x.propertyPath == group.Key.Name + ".enabled"); + var groupProperty = serializedObject.FindProperty(group.Key.Name); + + GUILayout.Space(5); + bool display = EditorGUIHelper.Header(groupProperty, enabledField); + if (!display) + continue; + + GUILayout.BeginHorizontal(); + { + GUILayout.Space(10); + GUILayout.BeginVertical(); + { + GUILayout.Space(3); + foreach (var field in group.Value.Where(x => x.propertyPath != group.Key.Name + ".enabled")) + { + // Special case for the tonemapping curve field + if (group.Key.FieldType == typeof(TonemappingColorGrading.TonemappingSettings) && + field.propertyType == SerializedPropertyType.AnimationCurve && + concreteTarget.tonemapping.tonemapper != TonemappingColorGrading.Tonemapper.Curve) + continue; + + // Special case for the neutral tonemapper + bool neutralParam = field.name.StartsWith("neutral"); + + if (group.Key.FieldType == typeof(TonemappingColorGrading.TonemappingSettings) && + concreteTarget.tonemapping.tonemapper != TonemappingColorGrading.Tonemapper.Neutral && + neutralParam) + continue; + + if (neutralParam) + EditorGUILayout.PropertyField(field, new GUIContent(ObjectNames.NicifyVariableName(field.name.Substring(7)))); + else + EditorGUILayout.PropertyField(field); + } + + // Bake button + if (group.Key.FieldType == typeof(TonemappingColorGrading.ColorGradingSettings)) + { + EditorGUI.BeginDisabledGroup(!enabledField.boolValue); + + if (GUILayout.Button("Export LUT as PNG", EditorStyles.miniButton)) + { + string path = EditorUtility.SaveFilePanelInProject("Export LUT as PNG", "LUT.png", "png", "Please enter a file name to save the LUT texture to"); + + if (!string.IsNullOrEmpty(path)) + { + Texture2D lut = concreteTarget.BakeLUT(); + + if (!concreteTarget.isGammaColorSpace) + { + var pixels = lut.GetPixels(); + + for (int i = 0; i < pixels.Length; i++) + pixels[i] = pixels[i].linear; + + lut.SetPixels(pixels); + lut.Apply(); + } + + byte[] bytes = lut.EncodeToPNG(); + System.IO.File.WriteAllBytes(path, bytes); + DestroyImmediate(lut); + + AssetDatabase.Refresh(); + TextureImporter importer = (TextureImporter)AssetImporter.GetAtPath(path); + SetLUTImportSettings(importer); + } + } + + EditorGUI.EndDisabledGroup(); + } + } + GUILayout.EndVertical(); + } + GUILayout.EndHorizontal(); + } + } + + public override void OnInspectorGUI() + { + if (s_Styles == null) + s_Styles = new Styles(); + + serializedObject.Update(); + + GUILayout.Label("All following effects will use LDR color buffers.", EditorStyles.miniBoldLabel); + + if (concreteTarget.tonemapping.enabled) + { + Camera camera = concreteTarget.GetComponent(); + + if (camera != null && !camera.hdr) + EditorGUILayout.HelpBox("The camera is not HDR enabled. This will likely break the tonemapper.", MessageType.Warning); + else if (!concreteTarget.validRenderTextureFormat) + EditorGUILayout.HelpBox("The input to tonemapper is not in HDR. Make sure that all effects prior to this are executed in HDR.", MessageType.Warning); + } + + if (concreteTarget.lut.enabled && concreteTarget.lut.texture != null) + { + if (!concreteTarget.validUserLutSize) + { + EditorGUILayout.HelpBox("Invalid LUT size. Should be \"height = sqrt(width)\" (e.g. 256x16).", MessageType.Error); + } + else + { + // Checks import settings on the lut, offers to fix them if invalid + TextureImporter importer = (TextureImporter)AssetImporter.GetAtPath(AssetDatabase.GetAssetPath(concreteTarget.lut.texture)); + bool valid = importer.anisoLevel == 0 + && importer.mipmapEnabled == false + && importer.linearTexture == true + && (importer.textureFormat == TextureImporterFormat.RGB24 || importer.textureFormat == TextureImporterFormat.AutomaticTruecolor); + + if (!valid) + { + EditorGUILayout.HelpBox("Invalid LUT import settings.", MessageType.Warning); + + GUILayout.Space(-32); + EditorGUILayout.BeginHorizontal(); + { + GUILayout.FlexibleSpace(); + if (GUILayout.Button("Fix", GUILayout.Width(60))) + { + SetLUTImportSettings(importer); + AssetDatabase.Refresh(); + } + GUILayout.Space(8); + } + EditorGUILayout.EndHorizontal(); + GUILayout.Space(11); + } + } + } + + DrawFields(); + + serializedObject.ApplyModifiedProperties(); + } + + private static readonly GUIContent k_HistogramTitle = new GUIContent("Histogram"); + public override GUIContent GetPreviewTitle() + { + return k_HistogramTitle; + } + + public override bool HasPreviewGUI() + { + return isHistogramSupported && targets.Length == 1 && concreteTarget != null && concreteTarget.enabled; + } + + public override void OnPreviewGUI(Rect r, GUIStyle background) + { + serializedObject.Update(); + + if (Event.current.type == EventType.Repaint) + { + // If m_HistogramRect isn't set the preview was just opened so refresh the render to get the histogram data + if (m_HistogramRect.width == 0 && m_HistogramRect.height == 0) + InternalEditorUtility.RepaintAllViews(); + + // Sizing + float width = Mathf.Min(512f, r.width); + float height = Mathf.Min(128f, r.height); + m_HistogramRect = new Rect( + Mathf.Floor(r.x + r.width / 2f - width / 2f), + Mathf.Floor(r.y + r.height / 2f - height / 2f), + width, height + ); + + if (m_HistogramTexture != null) + GUI.DrawTexture(m_HistogramRect, m_HistogramTexture); + } + + // Toolbar + GUILayout.BeginHorizontal(); + EditorGUI.BeginChangeCheck(); + { + concreteTarget.histogramRefreshOnPlay = GUILayout.Toggle(concreteTarget.histogramRefreshOnPlay, new GUIContent("Refresh on Play", "Keep refreshing the histogram in play mode; this may impact performances."), EditorStyles.miniButton); + GUILayout.FlexibleSpace(); + m_HistogramMode = (HistogramMode)EditorGUILayout.EnumPopup(m_HistogramMode); + } + GUILayout.EndHorizontal(); + + serializedObject.ApplyModifiedProperties(); + + if (EditorGUI.EndChangeCheck()) + InternalEditorUtility.RepaintAllViews(); + } + + private void OnFrameEnd(RenderTexture source) + { + if (Application.isPlaying && !concreteTarget.histogramRefreshOnPlay) + return; + + if (Mathf.Approximately(m_HistogramRect.width, 0) || Mathf.Approximately(m_HistogramRect.height, 0) || !isHistogramSupported) + return; + + // No need to process the full frame to get an histogram, resize the input to a max-size of 512 + int rw = Mathf.Min(Mathf.Max(source.width, source.height), 512); + RenderTexture rt = RenderTexture.GetTemporary(rw, rw, 0); + Graphics.Blit(source, rt); + UpdateHistogram(rt, m_HistogramRect, m_HistogramMode); + Repaint(); + RenderTexture.ReleaseTemporary(rt); + RenderTexture.active = null; + } + + private static readonly int[] k_EmptyBuffer = new int[256 << 2]; + void UpdateHistogram(RenderTexture source, Rect rect, HistogramMode mode) + { + if (m_HistogramMaterial == null) + m_HistogramMaterial = ImageEffectHelper.CheckShaderAndCreateMaterial(concreteTarget.histogramShader); + + if (m_HistogramBuffer == null) + m_HistogramBuffer = new ComputeBuffer(256, sizeof(uint) << 2); + + m_HistogramBuffer.SetData(k_EmptyBuffer); + + ComputeShader cs = concreteTarget.histogramComputeShader; + + int kernel = cs.FindKernel("KHistogramGather"); + cs.SetBuffer(kernel, "_Histogram", m_HistogramBuffer); + cs.SetTexture(kernel, "_Source", source); + + int[] channels = null; + switch (mode) + { + case HistogramMode.Luminance: + channels = new[] { 0, 0, 0, 1 }; + break; + case HistogramMode.RGB: + channels = new[] { 1, 1, 1, 0 }; + break; + case HistogramMode.Red: + channels = new[] { 1, 0, 0, 0 }; + break; + case HistogramMode.Green: + channels = new[] { 0, 1, 0, 0 }; + break; + case HistogramMode.Blue: + channels = new[] { 0, 0, 1, 0 }; + break; + } + + cs.SetInts("_Channels", channels); + cs.SetInt("_IsLinear", concreteTarget.isGammaColorSpace ? 0 : 1); + cs.Dispatch(kernel, Mathf.CeilToInt(source.width / 32f), Mathf.CeilToInt(source.height / 32f), 1); + + kernel = cs.FindKernel("KHistogramScale"); + cs.SetBuffer(kernel, "_Histogram", m_HistogramBuffer); + cs.SetFloat("_Height", rect.height); + cs.Dispatch(kernel, 1, 1, 1); + + if (m_HistogramTexture == null) + { + DestroyImmediate(m_HistogramTexture); + m_HistogramTexture = new RenderTexture((int)rect.width, (int)rect.height, 0, RenderTextureFormat.ARGB32); + m_HistogramTexture.hideFlags = HideFlags.HideAndDontSave; + } + + m_HistogramMaterial.SetBuffer("_Histogram", m_HistogramBuffer); + m_HistogramMaterial.SetVector("_Size", new Vector2(m_HistogramTexture.width, m_HistogramTexture.height)); + m_HistogramMaterial.SetColor("_ColorR", redCurveColor); + m_HistogramMaterial.SetColor("_ColorG", greenCurveColor); + m_HistogramMaterial.SetColor("_ColorB", blueCurveColor); + m_HistogramMaterial.SetColor("_ColorL", masterCurveColor); + m_HistogramMaterial.SetInt("_Channel", (int)mode); + Graphics.Blit(m_HistogramTexture, m_HistogramTexture, m_HistogramMaterial, (mode == HistogramMode.RGB) ? 1 : 0); + } + + public static class ColorWheel + { + // Constants + private const float PI_2 = Mathf.PI / 2f; + private const float PI2 = Mathf.PI * 2f; + + // hue Wheel + private static Texture2D s_WheelTexture; + private static float s_LastDiameter; + private static GUIStyle s_CenteredStyle; + + public static Color DoGUI(Rect area, string title, Color color, float diameter) + { + var labelrect = area; + labelrect.height = EditorGUIUtility.singleLineHeight; + + if (s_CenteredStyle == null) + { + s_CenteredStyle = new GUIStyle(GUI.skin.GetStyle("Label")) + { + alignment = TextAnchor.UpperCenter + }; + } + + GUI.Label(labelrect, title, s_CenteredStyle); + + // Figure out the wheel draw area + var wheelDrawArea = area; + wheelDrawArea.y += EditorGUIUtility.singleLineHeight; + wheelDrawArea.height = diameter; + + if (wheelDrawArea.width > wheelDrawArea.height) + { + wheelDrawArea.x += (wheelDrawArea.width - wheelDrawArea.height) / 2.0f; + wheelDrawArea.width = area.height; + } + + wheelDrawArea.width = wheelDrawArea.height; + + var radius = diameter / 2.0f; + Vector3 hsv; + Color.RGBToHSV(color, out hsv.x, out hsv.y, out hsv.z); + + // Retina/HDPI screens handling + wheelDrawArea.width /= pixelRatio; + wheelDrawArea.height /= pixelRatio; + float scaledRadius = radius / pixelRatio; + + if (Event.current.type == EventType.Repaint) + { + if (!Mathf.Approximately(diameter, s_LastDiameter)) + { + s_LastDiameter = diameter; + UpdateHueWheel((int)diameter); + } + + // Wheel + GUI.DrawTexture(wheelDrawArea, s_WheelTexture); + + // Thumb + Vector2 thumbPos = Vector2.zero; + float theta = hsv.x * PI2; + float len = hsv.y * scaledRadius; + thumbPos.x = Mathf.Cos(theta + PI_2); + thumbPos.y = Mathf.Sin(theta - PI_2); + thumbPos *= len; + Vector2 thumbSize = s_Styles.thumb2DSize; + Color oldColor = GUI.color; + GUI.color = Color.black; + Vector2 thumbSizeH = thumbSize / 2f; + Handles.color = Color.white; + Handles.DrawAAPolyLine(new Vector2(wheelDrawArea.x + scaledRadius + thumbSizeH.x, wheelDrawArea.y + scaledRadius + thumbSizeH.y), new Vector2(wheelDrawArea.x + scaledRadius + thumbPos.x, wheelDrawArea.y + scaledRadius + thumbPos.y)); + s_Styles.thumb2D.Draw(new Rect(wheelDrawArea.x + scaledRadius + thumbPos.x - thumbSizeH.x, wheelDrawArea.y + scaledRadius + thumbPos.y - thumbSizeH.y, thumbSize.x, thumbSize.y), false, false, false, false); + GUI.color = oldColor; + } + hsv = GetInput(wheelDrawArea, hsv, scaledRadius); + + var sliderDrawArea = wheelDrawArea; + sliderDrawArea.y = sliderDrawArea.yMax; + sliderDrawArea.height = EditorGUIUtility.singleLineHeight; + + hsv.y = GUI.HorizontalSlider(sliderDrawArea, hsv.y, 1e-04f, 1f); + color = Color.HSVToRGB(hsv.x, hsv.y, hsv.z); + return color; + } + + private static readonly int k_ThumbHash = "colorWheelThumb".GetHashCode(); + + private static Vector3 GetInput(Rect bounds, Vector3 hsv, float radius) + { + Event e = Event.current; + var id = GUIUtility.GetControlID(k_ThumbHash, FocusType.Passive, bounds); + + Vector2 mousePos = e.mousePosition; + Vector2 relativePos = mousePos - new Vector2(bounds.x, bounds.y); + + if (e.type == EventType.MouseDown && e.button == 0 && GUIUtility.hotControl == 0) + { + if (bounds.Contains(mousePos)) + { + Vector2 center = new Vector2(bounds.x + radius, bounds.y + radius); + float dist = Vector2.Distance(center, mousePos); + + if (dist <= radius) + { + e.Use(); + GetWheelHueSaturation(relativePos.x, relativePos.y, radius, out hsv.x, out hsv.y); + GUIUtility.hotControl = id; + } + } + } + else if (e.type == EventType.MouseDrag && e.button == 0 && GUIUtility.hotControl == id) + { + Vector2 center = new Vector2(bounds.x + radius, bounds.y + radius); + float dist = Vector2.Distance(center, mousePos); + + if (dist <= radius) + { + e.Use(); + GetWheelHueSaturation(relativePos.x, relativePos.y, radius, out hsv.x, out hsv.y); + } + } + else if (e.type == EventType.MouseUp && e.button == 0 && GUIUtility.hotControl == id) + { + e.Use(); + GUIUtility.hotControl = 0; + } + + return hsv; + } + + private static 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 : PI2 + hue) / PI2; + saturation = Mathf.Clamp01(d); + } + + private static void UpdateHueWheel(int diameter) + { + CleanTexture(s_WheelTexture); + s_WheelTexture = MakeTexture(diameter); + + var radius = diameter / 2.0f; + + Color[] pixels = s_WheelTexture.GetPixels(); + + for (int y = 0; y < diameter; y++) + { + for (int x = 0; x < diameter; x++) + { + int index = y * diameter + x; + float dx = (x - radius) / radius; + float dy = (y - radius) / radius; + float d = Mathf.Sqrt(dx * dx + dy * dy); + + // Out of the wheel, early exit + if (d >= 1f) + { + pixels[index] = new Color(0f, 0f, 0f, 0f); + continue; + } + + // red (0) on top, counter-clockwise (industry standard) + float saturation = d; + float hue = Mathf.Atan2(dx, dy); + hue = 1f - ((hue > 0) ? hue : PI2 + hue) / PI2; + Color color = Color.HSVToRGB(hue, saturation, 1f); + + // Quick & dirty antialiasing + color.a = (saturation > 0.99) ? (1f - saturation) * 100f : 1f; + + pixels[index] = color; + } + } + + s_WheelTexture.SetPixels(pixels); + s_WheelTexture.Apply(); + } + + private static Texture2D MakeTexture(int dimension) + { + return new Texture2D(dimension, dimension, TextureFormat.ARGB32, false, true) + { + filterMode = FilterMode.Point, + wrapMode = TextureWrapMode.Clamp, + hideFlags = HideFlags.HideAndDontSave, + alphaIsTransparency = true + }; + } + + private static void CleanTexture(Texture2D texture) + { + if (texture != null) + DestroyImmediate(texture); + } + + public static float GetColorWheelHeight(int renderSizePerWheel) + { + // wheel height + title label + alpha slider + return renderSizePerWheel + 2 * EditorGUIUtility.singleLineHeight; + } + } + } +} diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/TonemappingColorGrading/Editor/TonemappingColorGradingEditor.cs.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/TonemappingColorGrading/Editor/TonemappingColorGradingEditor.cs.meta new file mode 100644 index 0000000..51e5b4a --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/TonemappingColorGrading/Editor/TonemappingColorGradingEditor.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 64bb64b30a05a0d4b8afe58a356fc8fb +timeCreated: 1441354689 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/TonemappingColorGrading/Helpers.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/TonemappingColorGrading/Helpers.meta new file mode 100644 index 0000000..e7cf980 --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/TonemappingColorGrading/Helpers.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 54915b6fdd14fd042add2d153a8b892d +folderAsset: yes +timeCreated: 1454073138 +licenseType: Store +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/TonemappingColorGrading/Helpers/NeutralLUT16.png b/IronToad_UnityProject/Assets/Standard Assets/Effects/TonemappingColorGrading/Helpers/NeutralLUT16.png new file mode 100644 index 0000000000000000000000000000000000000000..0e4bda409753082066271b7860b894eefee4e1fa GIT binary patch literal 982 zcmaJ=J#W)M7``?PRh5W}0SN|lau`4&cI?D%W5oo=PTN$tijqjpz!1m2Hdbn%u`i92 zg^!IL79{=xQa1z=bOhE;u&}{Wi47(s&S^e65G>1n-_!Fx@7HtBYP(yh)$6MOfK+u` zuLH0|O|Z7IOut9R(hd5%Mk+1R!24ui1_-D&?jTro%>z_NragT42^9fIFix{YTE>0Z z!Y*sZ7&dbKm`R$gwy$;P^tJ5OWAZ zh9WZI&?9D)@xt_!K}Vq#I6iT(2V+LFgZo5bXr<>Zxc-dR3nycu1LGpo=Xf?7w=@MB z#{Z$NJ41)0j^_3LlQ?V+eZ7q_2|Q~9zMAd}#riSgldinT5#IP78{Y7GhA z+H*V`55n7HykW>yFC?aCp{lMhl!0{|Th>)g6-7bQq>Td4SHyCK&#D_aQINEXww{-! zu{yT;F7n7U)}F`e3u9v`xIWFSqrf>r_GW-xIBr>X7T2OKgrd2Du`s;H0 F>0h(GEH3~6 literal 0 HcmV?d00001 diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/TonemappingColorGrading/Helpers/NeutralLUT16.png.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/TonemappingColorGrading/Helpers/NeutralLUT16.png.meta new file mode 100644 index 0000000..667bfbb --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/TonemappingColorGrading/Helpers/NeutralLUT16.png.meta @@ -0,0 +1,57 @@ +fileFormatVersion: 2 +guid: 36c322ded1667bc4a867aea5e662c51b +timeCreated: 1454073156 +licenseType: Store +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + linearTexture: 1 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + cubemapConvolution: 0 + cubemapConvolutionSteps: 7 + cubemapConvolutionExponent: 1.5 + seamlessCubemap: 0 + textureFormat: 3 + maxTextureSize: 2048 + textureSettings: + filterMode: -1 + aniso: 0 + mipBias: -1 + wrapMode: -1 + nPOTScale: 1 + lightmap: 0 + rGBM: 0 + compressionQuality: 50 + allowsAlphaSplitting: 0 + 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 + alphaIsTransparency: 0 + textureType: 5 + buildTargetSettings: [] + spriteSheet: + sprites: [] + outline: [] + spritePackingTag: + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/TonemappingColorGrading/Helpers/NeutralLUT32.png b/IronToad_UnityProject/Assets/Standard Assets/Effects/TonemappingColorGrading/Helpers/NeutralLUT32.png new file mode 100644 index 0000000000000000000000000000000000000000..b8724d41d175d8e44964fd27d9d48706e3a9f698 GIT binary patch literal 1165 zcmaJ=O=uHA6rNPkQWSC!K}9;O2nuF5n`F0UZEV{7Xuy<`23u6H+udoirn|H5PEA_W zh9Zi16$DWcJc%NL;6YLAK}19mJSghPg9jChv>-(&zKKosU<~>8&3nA>dv9jmobBt~ zv$kzx8$xJpZg0AP&`MY$+}Z-)6_+l52eW}?23bEHVHMpYsN1B&1m|phloW_=P8@wk zIw4iCii2!0zfUu$E$Tc+tlBQuLY-YzS2xOp;bAgrISFC*{v!cfW5o11@f43oqqrDUaxk zdPPdd8mHJ-qKx__>f%(tink3|j!7&2_IiFkujL${>5f5i>4X3ZqGg#{M(t3tJ3C@2 zb!S|bGfF(G^mK=#J()}!w0khtpGD~bLV-Xo-CeA{ z`}$sPJCzJ(9>1X@?XeJy9zP@t!$*Sq+EA9Ex$n`sS?@e91a^}t4(;Hn=2al9b zE{5CZDi3GNi=XJ?%O59ROkG^KIlc~|U=KXBWD$Km4K^MaS^(=9Wr z!0-o-0Vn{NZ$%es0fe`qG4PUrI<2%BedB%~dJCoosMB6)=mW57SJ7=w=4b^Z0VvTj zvvmmkHna&mUbhB72Ugd1feEfdDi{o?EgWiDgASfg9{;#dI|l)j%k-vi^$bn_0vaAv AivR!s literal 0 HcmV?d00001 diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/TonemappingColorGrading/Helpers/NeutralLUT32.png.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/TonemappingColorGrading/Helpers/NeutralLUT32.png.meta new file mode 100644 index 0000000..6e85fa8 --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/TonemappingColorGrading/Helpers/NeutralLUT32.png.meta @@ -0,0 +1,57 @@ +fileFormatVersion: 2 +guid: 6ac6980bae76ac241971e97191b6c30c +timeCreated: 1454073159 +licenseType: Store +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + linearTexture: 1 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + cubemapConvolution: 0 + cubemapConvolutionSteps: 7 + cubemapConvolutionExponent: 1.5 + seamlessCubemap: 0 + textureFormat: 3 + maxTextureSize: 2048 + textureSettings: + filterMode: -1 + aniso: 0 + mipBias: -1 + wrapMode: -1 + nPOTScale: 1 + lightmap: 0 + rGBM: 0 + compressionQuality: 50 + allowsAlphaSplitting: 0 + 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 + alphaIsTransparency: 0 + textureType: 5 + buildTargetSettings: [] + spriteSheet: + sprites: [] + outline: [] + spritePackingTag: + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/TonemappingColorGrading/Resources.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/TonemappingColorGrading/Resources.meta new file mode 100644 index 0000000..3e60aaf --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/TonemappingColorGrading/Resources.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 710c12a933657234f859808d82c5dd8b +folderAsset: yes +timeCreated: 1453901184 +licenseType: Store +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/TonemappingColorGrading/Resources/HistogramCompute.compute b/IronToad_UnityProject/Assets/Standard Assets/Effects/TonemappingColorGrading/Resources/HistogramCompute.compute new file mode 100644 index 0000000..0e45d61 --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/TonemappingColorGrading/Resources/HistogramCompute.compute @@ -0,0 +1,85 @@ +#include "UnityCG.cginc" + +RWStructuredBuffer _Histogram; +Texture2D _Source; + +CBUFFER_START (Params) + uint4 _Channels; + uint _IsLinear; + float _Height; +CBUFFER_END + +// Gathering pass +groupshared uint4 gs_histogram[256]; + +#pragma kernel KHistogramGather +[numthreads(32,32,1)] // Needs at least 256 threads per group +void KHistogramGather(uint3 id : SV_DispatchThreadID, uint3 _group_thread_id : SV_GroupThreadID) +{ + const uint thread_id = _group_thread_id.y * 32 + _group_thread_id.x; + + if (thread_id < 256) + gs_histogram[thread_id] = uint4(0, 0, 0, 0); + + uint sw, sh; + _Source.GetDimensions(sw, sh); + + GroupMemoryBarrierWithGroupSync(); + + if (id.x < sw && id.y < sh) + { + // We want a gamma histogram (like Photoshop & all) + float3 color = saturate(_Source[id.xy].xyz); + if (_IsLinear > 0) + color = LinearToGammaSpace(color); + + // Convert color & luminance to histogram bin + uint3 idx_c = (uint3)(round(color * 255.0)); + uint idx_l = (uint)(round(dot(color.rgb, float3(0.2126, 0.7152, 0.0722)) * 255.0)); + + // Fill the group shared histogram + if (_Channels.r > 0) InterlockedAdd(gs_histogram[idx_c.x].x, 1); // Red + if (_Channels.g > 0) InterlockedAdd(gs_histogram[idx_c.y].y, 1); // Green + if (_Channels.b > 0) InterlockedAdd(gs_histogram[idx_c.z].z, 1); // Blue + if (_Channels.a > 0) InterlockedAdd(gs_histogram[idx_l].w, 1); // Luminance + } + + GroupMemoryBarrierWithGroupSync(); + + // Merge + if (thread_id < 256) + { + uint4 h = gs_histogram[thread_id]; + InterlockedAdd(_Histogram[thread_id].x, h.x); // Red + InterlockedAdd(_Histogram[thread_id].y, h.y); // Green + InterlockedAdd(_Histogram[thread_id].z, h.z); // Blue + InterlockedAdd(_Histogram[thread_id].w, h.w); // Luminance + } +} + +// Scaling pass +groupshared uint4 gs_pyramid[256]; + +#pragma kernel KHistogramScale +[numthreads(16,16,1)] +void KHistogramScale(uint3 _group_thread_id : SV_GroupThreadID) +{ + const uint thread_id = _group_thread_id.y * 16 + _group_thread_id.x; + gs_pyramid[thread_id] = _Histogram[thread_id]; + + GroupMemoryBarrierWithGroupSync(); + + // Parallel reduction to find the max value + [unroll] + for(uint i = 256 >> 1; i > 0; i >>= 1) + { + if(thread_id < i) + gs_pyramid[thread_id] = max(gs_pyramid[thread_id], gs_pyramid[thread_id + i]); + + GroupMemoryBarrierWithGroupSync(); + } + + // Actual scaling + float4 factor = _Height / (float4)gs_pyramid[0]; + _Histogram[thread_id] = (uint4)round(_Histogram[thread_id] * factor); +} diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/TonemappingColorGrading/Resources/HistogramCompute.compute.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/TonemappingColorGrading/Resources/HistogramCompute.compute.meta new file mode 100644 index 0000000..3dc83f2 --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/TonemappingColorGrading/Resources/HistogramCompute.compute.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 5ee4b74fa28a3e74e89423dd49705fc5 +timeCreated: 1436170077 +licenseType: Store +ComputeShaderImporter: + currentBuildTarget: 5 + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/TonemappingColorGrading/Resources/HistogramRender.shader b/IronToad_UnityProject/Assets/Standard Assets/Effects/TonemappingColorGrading/Resources/HistogramRender.shader new file mode 100644 index 0000000..c78673c --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/TonemappingColorGrading/Resources/HistogramRender.shader @@ -0,0 +1,104 @@ +Shader "Hidden/TonemappingColorGradingHistogram" +{ + SubShader + { + ZTest Always Cull Off ZWrite Off + Fog { Mode off } + + CGINCLUDE + + #pragma fragmentoption ARB_precision_hint_fastest + #pragma target 5.0 + #include "UnityCG.cginc" + + struct v_data + { + float4 pos : SV_POSITION; + float2 uv : TEXCOORD0; + }; + + StructuredBuffer _Histogram; + float2 _Size; + uint _Channel; + float4 _ColorR; + float4 _ColorG; + float4 _ColorB; + float4 _ColorL; + + v_data vert(appdata_img v) + { + v_data o; + o.pos = mul(UNITY_MATRIX_MVP, v.vertex); + o.uv = v.texcoord; + return o; + } + + float4 frag_channel(v_data i) : SV_Target + { + const float4 COLORS[4] = { _ColorR, _ColorG, _ColorB, _ColorL }; + + float remapI = i.uv.x * 255.0; + uint index = floor(remapI); + float delta = frac(remapI); + float v1 = _Histogram[index][_Channel]; + float v2 = _Histogram[min(index + 1, 255)][_Channel]; + float h = v1 * (1.0 - delta) + v2 * delta; + uint y = (uint)round(i.uv.y * _Size.y); + + float4 color = float4(0.0, 0.0, 0.0, 0.0); + float fill = step(y, h); + color = lerp(color, COLORS[_Channel], fill); + return color; + } + + float4 frag_rgb(v_data i) : SV_Target + { + const float4 COLORS[3] = { _ColorR, _ColorG, _ColorB }; + + float4 targetColor = float4(0.0, 0.0, 0.0, 0.0); + float4 emptyColor = float4(0.0, 0.0, 0.0, 0.0); + float fill = 0; + + for (int j = 0; j < 3; j++) + { + float remapI = i.uv.x * 255.0; + uint index = floor(remapI); + float delta = frac(remapI); + float v1 = _Histogram[index][j]; + float v2 = _Histogram[min(index + 1, 255)][j]; + float h = v1 * (1.0 - delta) + v2 * delta; + uint y = (uint)round(i.uv.y * _Size.y); + float fill = step(y, h); + float4 color = lerp(emptyColor, COLORS[j], fill); + targetColor += color; + } + + return saturate(targetColor); + } + + ENDCG + + // (0) Channel + Pass + { + CGPROGRAM + + #pragma vertex vert + #pragma fragment frag_channel + + ENDCG + } + + // (1) RGB + Pass + { + CGPROGRAM + + #pragma vertex vert + #pragma fragment frag_rgb + + ENDCG + } + } + FallBack off +} diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/TonemappingColorGrading/Resources/HistogramRender.shader.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/TonemappingColorGrading/Resources/HistogramRender.shader.meta new file mode 100644 index 0000000..75e246a --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/TonemappingColorGrading/Resources/HistogramRender.shader.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 9a8e838691462194482a43a02e424876 +timeCreated: 1436173774 +licenseType: Store +ShaderImporter: + defaultTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/TonemappingColorGrading/Resources/TonemappingColorGrading.cginc b/IronToad_UnityProject/Assets/Standard Assets/Effects/TonemappingColorGrading/Resources/TonemappingColorGrading.cginc new file mode 100644 index 0000000..bad7822 --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/TonemappingColorGrading/Resources/TonemappingColorGrading.cginc @@ -0,0 +1,260 @@ +#include "UnityCG.cginc" + +sampler2D _MainTex; +half4 _MainTex_TexelSize; + +half _Exposure; +half _ToneCurveRange; +sampler2D _ToneCurve; +half4 _NeutralTonemapperParams1; +half4 _NeutralTonemapperParams2; + +sampler2D _InternalLutTex; +half3 _InternalLutParams; + +sampler2D _UserLutTex; +half4 _UserLutParams; + +sampler2D _LumTex; +half _AdaptationSpeed; +half _MiddleGrey; +half _AdaptationMin; +half _AdaptationMax; + +inline half LinToPerceptual(half3 color) +{ + half lum = Luminance(color); + return log(max(lum, 0.001)); +} + +inline half PerceptualToLin(half f) +{ + return exp(f); +} + +half4 frag_log(v2f_img i) : SV_Target +{ + half sum = 0.0; + sum += LinToPerceptual(tex2D(_MainTex, i.uv + _MainTex_TexelSize.xy * half2(-1,-1)).rgb); + sum += LinToPerceptual(tex2D(_MainTex, i.uv + _MainTex_TexelSize.xy * half2( 1, 1)).rgb); + sum += LinToPerceptual(tex2D(_MainTex, i.uv + _MainTex_TexelSize.xy * half2(-1, 1)).rgb); + sum += LinToPerceptual(tex2D(_MainTex, i.uv + _MainTex_TexelSize.xy * half2( 1,-1)).rgb); + half avg = sum / 4.0; + return half4(avg, avg, avg, avg); +} + +half4 frag_exp(v2f_img i) : SV_Target +{ + half sum = 0.0; + sum += tex2D(_MainTex, i.uv + _MainTex_TexelSize.xy * half2(-1,-1)).x; + sum += tex2D(_MainTex, i.uv + _MainTex_TexelSize.xy * half2( 1, 1)).x; + sum += tex2D(_MainTex, i.uv + _MainTex_TexelSize.xy * half2( 1,-1)).x; + sum += tex2D(_MainTex, i.uv + _MainTex_TexelSize.xy * half2(-1, 1)).x; + half avg = PerceptualToLin(sum / 4.0); + return half4(avg, avg, avg, saturate(0.0125 * _AdaptationSpeed)); +} + +half3 apply_lut(sampler2D tex, half3 uvw, half3 scaleOffset) +{ + // Strip format where `height = sqrt(width)` + uvw.z *= scaleOffset.z; + half shift = floor(uvw.z); + uvw.xy = uvw.xy * scaleOffset.z * scaleOffset.xy + scaleOffset.xy * 0.5; + uvw.x += shift * scaleOffset.y; + uvw.xyz = lerp(tex2D(tex, uvw.xy).rgb, tex2D(tex, uvw.xy + half2(scaleOffset.y, 0)).rgb, uvw.z - shift); + return uvw; +} + +half3 ToCIE(half3 color) +{ + // RGB -> XYZ conversion + // http://www.w3.org/Graphics/Color/sRGB + // The official sRGB to XYZ conversion matrix is (following ITU-R BT.709) + // 0.4125 0.3576 0.1805 + // 0.2126 0.7152 0.0722 + // 0.0193 0.1192 0.9505 + half3x3 RGB2XYZ = { 0.5141364, 0.3238786, 0.16036376, 0.265068, 0.67023428, 0.06409157, 0.0241188, 0.1228178, 0.84442666 }; + half3 XYZ = mul(RGB2XYZ, color.rgb); + + // XYZ -> Yxy conversion + half3 Yxy; + Yxy.r = XYZ.g; + half temp = dot(half3(1.0, 1.0, 1.0), XYZ.rgb); + Yxy.gb = XYZ.rg / temp; + return Yxy; +} + +half3 FromCIE(half3 Yxy) +{ + // Yxy -> XYZ conversion + half3 XYZ; + XYZ.r = Yxy.r * Yxy.g / Yxy.b; + XYZ.g = Yxy.r; + + // Copy luminance Y + XYZ.b = Yxy.r * (1 - Yxy.g - Yxy.b) / Yxy.b; + + // XYZ -> RGB conversion + // The official XYZ to sRGB conversion matrix is (following ITU-R BT.709) + // 3.2410 -1.5374 -0.4986 + // -0.9692 1.8760 0.0416 + // 0.0556 -0.2040 1.0570 + half3x3 XYZ2RGB = { 2.5651, -1.1665, -0.3986, -1.0217, 1.9777, 0.0439, 0.0753, -0.2543, 1.1892 }; + return mul(XYZ2RGB, XYZ); +} + +half3 tonemapACES(half3 color) +{ + color *= _Exposure; + + // See https://knarkowicz.wordpress.com/2016/01/06/aces-filmic-tone-mapping-curve/ + const half a = 2.51; + const half b = 0.03; + const half c = 2.43; + const half d = 0.59; + const half e = 0.14; + return saturate((color * (a * color + b)) / (color * (c * color + d) + e)); +} + +half3 tonemapPhotographic(half3 color) +{ + color *= _Exposure; + return 1.0 - exp2(-color); +} + +half3 tonemapHable(half3 color) +{ + const half a = 0.15; + const half b = 0.50; + const half c = 0.10; + const half d = 0.20; + const half e = 0.02; + const half f = 0.30; + const half w = 11.2; + + color *= _Exposure * 2.0; + half3 curr = ((color * (a * color + c * b) + d * e) / (color * (a * color + b) + d * f)) - e / f; + color = w; + half3 whiteScale = 1.0 / (((color * (a * color + c * b) + d * e) / (color * (a * color + b) + d * f)) - e / f); + return curr * whiteScale; +} + +half3 tonemapHejlDawson(half3 color) +{ + const half a = 6.2; + const half b = 0.5; + const half c = 1.7; + const half d = 0.06; + + color *= _Exposure; + color = max((0.0).xxx, color - (0.004).xxx); + color = (color * (a * color + b)) / (color * (a * color + c) + d); + return color * color; +} + +half3 tonemapReinhard(half3 color) +{ + half lum = Luminance(color); + half lumTm = lum * _Exposure; + half scale = lumTm / (1.0 + lumTm); + return color * scale / lum; +} + +half3 tonemapCurve(half3 color) +{ + color *= _Exposure; + half3 cie = ToCIE(color); + half newLum = tex2D(_ToneCurve, half2(cie.r * _ToneCurveRange, 0.5)).r; + cie.r = newLum; + return FromCIE(cie); +} + +half3 neutralCurve(half3 x, half a, half b, half c, half d, half e, half f) +{ + return ((x * (a * x + c * b) + d * e) / (x * (a * x + b) + d * f)) - e / f; +} + +half3 tonemapNeutral(half3 color) +{ + color *= _Exposure; + + // Tonemap + half a = _NeutralTonemapperParams1.x; + half b = _NeutralTonemapperParams1.y; + half c = _NeutralTonemapperParams1.z; + half d = _NeutralTonemapperParams1.w; + half e = _NeutralTonemapperParams2.x; + half f = _NeutralTonemapperParams2.y; + half whiteLevel = _NeutralTonemapperParams2.z; + half whiteClip = _NeutralTonemapperParams2.w; + + half3 whiteScale = (1.0).xxx / neutralCurve(whiteLevel, a, b, c, d, e, f); + color = neutralCurve(color * whiteScale, a, b, c, d, e, f); + color *= whiteScale; + + // Post-curve white point adjustment + color = color / whiteClip.xxx; + + return color; +} + +half4 frag_tcg(v2f_img i) : SV_Target +{ + half4 color = tex2D(_MainTex, i.uv); + +#if UNITY_COLORSPACE_GAMMA + color.rgb = GammaToLinearSpace(color.rgb); +#endif + +#if ENABLE_EYE_ADAPTATION + // Fast eye adaptation + half avg_luminance = tex2D(_LumTex, i.uv).x; + half linear_exposure = _MiddleGrey / avg_luminance; + color.rgb *= max(_AdaptationMin, min(_AdaptationMax, linear_exposure)); +#endif + +#if defined(TONEMAPPING_ACES) + color.rgb = tonemapACES(color.rgb); +#elif defined(TONEMAPPING_CURVE) + color.rgb = tonemapCurve(color.rgb); +#elif defined(TONEMAPPING_HABLE) + color.rgb = tonemapHable(color.rgb); +#elif defined(TONEMAPPING_HEJL_DAWSON) + color.rgb = tonemapHejlDawson(color.rgb); +#elif defined(TONEMAPPING_PHOTOGRAPHIC) + color.rgb = tonemapPhotographic(color.rgb); +#elif defined(TONEMAPPING_REINHARD) + color.rgb = tonemapReinhard(color.rgb); +#elif defined(TONEMAPPING_NEUTRAL) + color.rgb = tonemapNeutral(color.rgb); +#endif + +#if ENABLE_COLOR_GRADING + // LUT color grading + color.rgb = apply_lut(_InternalLutTex, saturate(color.rgb), _InternalLutParams); +#endif + +#if ENABLE_DITHERING + // Interleaved Gradient Noise from http://www.iryoku.com/next-generation-post-processing-in-call-of-duty-advanced-warfare (slide 122) + half3 magic = float3(0.06711056, 0.00583715, 52.9829189); + half gradient = frac(magic.z * frac(dot(i.uv / _MainTex_TexelSize, magic.xy))) / 255.0; + color.rgb -= gradient.xxx; +#endif + +#if UNITY_COLORSPACE_GAMMA + color.rgb = LinearToGammaSpace(color.rgb); +#endif + +#if ENABLE_USER_LUT + #if !UNITY_COLORSPACE_GAMMA + half3 lc = apply_lut(_UserLutTex, saturate(LinearToGammaSpace(color.rgb)), _UserLutParams.xyz); + lc = GammaToLinearSpace(lc); + #else + half3 lc = apply_lut(_UserLutTex, saturate(color.rgb), _UserLutParams.xyz); + #endif + + color.rgb = lerp(color.rgb, lc, _UserLutParams.w); +#endif + + return color; +} diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/TonemappingColorGrading/Resources/TonemappingColorGrading.cginc.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/TonemappingColorGrading/Resources/TonemappingColorGrading.cginc.meta new file mode 100644 index 0000000..5609bcd --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/TonemappingColorGrading/Resources/TonemappingColorGrading.cginc.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: a7e68b07525bc7f459ff03bf6cba782a +timeCreated: 1453723607 +licenseType: Store +ShaderImporter: + defaultTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/TonemappingColorGrading/Resources/TonemappingColorGrading.shader b/IronToad_UnityProject/Assets/Standard Assets/Effects/TonemappingColorGrading/Resources/TonemappingColorGrading.shader new file mode 100644 index 0000000..ab303dd --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/TonemappingColorGrading/Resources/TonemappingColorGrading.shader @@ -0,0 +1,305 @@ +Shader "Hidden/TonemappingColorGrading" +{ + Properties + { + _MainTex ("Texture", 2D) = "white" {} + } + + CGINCLUDE + + #pragma vertex vert_img + #pragma fragmentoption ARB_precision_hint_fastest + #pragma target 3.0 + + ENDCG + + SubShader + { + ZTest Always Cull Off ZWrite Off + Fog { Mode off } + + // Lut generator + Pass + { + CGPROGRAM + + #pragma fragment frag_lut_gen + #include "TonemappingColorGrading.cginc" + + half3 _WhiteBalance; + half3 _Lift; + half3 _Gamma; + half3 _Gain; + half3 _ContrastGainGamma; + half _Vibrance; + half3 _HSV; + half3 _ChannelMixerRed; + half3 _ChannelMixerGreen; + half3 _ChannelMixerBlue; + sampler2D _CurveTex; + half _Contribution; + + static const half3x3 LIN_2_LMS_MAT = { + 3.90405e-1, 5.49941e-1, 8.92632e-3, + 7.08416e-2, 9.63172e-1, 1.35775e-3, + 2.31082e-2, 1.28021e-1, 9.36245e-1 + }; + + static const half3x3 LMS_2_LIN_MAT = { + 2.85847e+0, -1.62879e+0, -2.48910e-2, + -2.10182e-1, 1.15820e+0, 3.24281e-4, + -4.18120e-2, -1.18169e-1, 1.06867e+0 + }; + + half3 rgb_to_hsv(half3 c) + { + half4 K = half4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0); + half4 p = lerp(half4(c.bg, K.wz), half4(c.gb, K.xy), step(c.b, c.g)); + half4 q = lerp(half4(p.xyw, c.r), half4(c.r, p.yzx), step(p.x, c.r)); + half d = q.x - min(q.w, q.y); + half e = 1.0e-4; + return half3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x); + } + + half3 hsv_to_rgb(half3 c) + { + half4 K = half4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0); + half3 p = abs(frac(c.xxx + K.xyz) * 6.0 - K.www); + return c.z * lerp(K.xxx, saturate(p - K.xxx), c.y); + } + + // CG's fmod() is not the same as GLSL's mod() with negative values, we'll use our own + inline half gmod(half x, half y) + { + return x - y * floor(x / y); + } + + half4 frag_lut_gen(v2f_img i) : SV_Target + { + half3 neutral_lut = tex2D(_MainTex, i.uv).rgb; + half3 final_lut = neutral_lut; + + // White balance + half3 lms = mul(LIN_2_LMS_MAT, final_lut); + lms *= _WhiteBalance; + final_lut = mul(LMS_2_LIN_MAT, lms); + + // Lift/gamma/gain + final_lut = _Gain * (_Lift * (1.0 - final_lut) + pow(final_lut, _Gamma)); + final_lut = max(final_lut, 0.0); + + // Hue/saturation/value + half3 hsv = rgb_to_hsv(final_lut); + hsv.x = gmod(hsv.x + _HSV.x, 1.0); + hsv.yz *= _HSV.yz; + final_lut = saturate(hsv_to_rgb(hsv)); + + // Vibrance + half sat = max(final_lut.r, max(final_lut.g, final_lut.b)) - min(final_lut.r, min(final_lut.g, final_lut.b)); + final_lut = lerp(Luminance(final_lut).xxx, final_lut, (1.0 + (_Vibrance * (1.0 - (sign(_Vibrance) * sat))))); + + // Contrast + final_lut = saturate((final_lut - 0.5) * _ContrastGainGamma.x + 0.5); + + // Gain + half f = pow(2.0, _ContrastGainGamma.y) * 0.5; + final_lut = (final_lut < 0.5) ? pow(final_lut, _ContrastGainGamma.y) * f : 1.0 - pow(1.0 - final_lut, _ContrastGainGamma.y) * f; + + // Gamma + final_lut = pow(final_lut, _ContrastGainGamma.z); + + // Color mixer + final_lut = half3( + dot(final_lut, _ChannelMixerRed), + dot(final_lut, _ChannelMixerGreen), + dot(final_lut, _ChannelMixerBlue) + ); + + // Curves + half mr = tex2D(_CurveTex, half2(final_lut.r, 0.5)).a; + half mg = tex2D(_CurveTex, half2(final_lut.g, 0.5)).a; + half mb = tex2D(_CurveTex, half2(final_lut.b, 0.5)).a; + final_lut = half3(mr, mg, mb); + half r = tex2D(_CurveTex, half2(final_lut.r, 0.5)).r; + half g = tex2D(_CurveTex, half2(final_lut.g, 0.5)).g; + half b = tex2D(_CurveTex, half2(final_lut.b, 0.5)).b; + final_lut = half3(r, g, b); + + return half4(final_lut, 1.0); + } + + ENDCG + } + + // The three following passes are used to get an average log luminance using a downsample pyramid + Pass + { + CGPROGRAM + #pragma fragment frag_log + #include "TonemappingColorGrading.cginc" + ENDCG + } + + Pass + { + Blend SrcAlpha OneMinusSrcAlpha + + CGPROGRAM + #pragma fragment frag_exp + #include "TonemappingColorGrading.cginc" + ENDCG + } + + Pass + { + Blend Off + + CGPROGRAM + #pragma fragment frag_exp + #include "TonemappingColorGrading.cginc" + ENDCG + } + + // Tonemapping off + Pass + { + CGPROGRAM + #pragma multi_compile __ UNITY_COLORSPACE_GAMMA + #pragma multi_compile __ ENABLE_COLOR_GRADING + #pragma multi_compile __ ENABLE_EYE_ADAPTATION + #pragma multi_compile __ ENABLE_DITHERING + #pragma multi_compile __ ENABLE_USER_LUT + #pragma fragment frag_tcg + #include "TonemappingColorGrading.cginc" + ENDCG + } + + // Tonemapping (ACES) + Pass + { + CGPROGRAM + #pragma multi_compile __ UNITY_COLORSPACE_GAMMA + #pragma multi_compile __ ENABLE_COLOR_GRADING + #pragma multi_compile __ ENABLE_EYE_ADAPTATION + #pragma multi_compile __ ENABLE_DITHERING + #pragma multi_compile __ ENABLE_USER_LUT + #pragma fragment frag_tcg + #define TONEMAPPING_ACES + #include "TonemappingColorGrading.cginc" + ENDCG + } + + // Tonemapping (Curve) + Pass + { + CGPROGRAM + #pragma multi_compile __ UNITY_COLORSPACE_GAMMA + #pragma multi_compile __ ENABLE_COLOR_GRADING + #pragma multi_compile __ ENABLE_EYE_ADAPTATION + #pragma multi_compile __ ENABLE_DITHERING + #pragma multi_compile __ ENABLE_USER_LUT + #pragma fragment frag_tcg + #define TONEMAPPING_CURVE + #include "TonemappingColorGrading.cginc" + ENDCG + } + + // Tonemapping (Hable) + Pass + { + CGPROGRAM + #pragma multi_compile __ UNITY_COLORSPACE_GAMMA + #pragma multi_compile __ ENABLE_COLOR_GRADING + #pragma multi_compile __ ENABLE_EYE_ADAPTATION + #pragma multi_compile __ ENABLE_DITHERING + #pragma multi_compile __ ENABLE_USER_LUT + #pragma fragment frag_tcg + #define TONEMAPPING_HABLE + #include "TonemappingColorGrading.cginc" + ENDCG + } + + // Tonemapping (Hejl-Dawson) + Pass + { + CGPROGRAM + #pragma multi_compile __ UNITY_COLORSPACE_GAMMA + #pragma multi_compile __ ENABLE_COLOR_GRADING + #pragma multi_compile __ ENABLE_EYE_ADAPTATION + #pragma multi_compile __ ENABLE_DITHERING + #pragma multi_compile __ ENABLE_USER_LUT + #pragma fragment frag_tcg + #define TONEMAPPING_HEJL_DAWSON + #include "TonemappingColorGrading.cginc" + ENDCG + } + + // Tonemapping (Photographic) + Pass + { + CGPROGRAM + #pragma multi_compile __ UNITY_COLORSPACE_GAMMA + #pragma multi_compile __ ENABLE_COLOR_GRADING + #pragma multi_compile __ ENABLE_EYE_ADAPTATION + #pragma multi_compile __ ENABLE_DITHERING + #pragma multi_compile __ ENABLE_USER_LUT + #pragma fragment frag_tcg + #define TONEMAPPING_PHOTOGRAPHIC + #include "TonemappingColorGrading.cginc" + ENDCG + } + + // Tonemapping (Reinhard) + Pass + { + CGPROGRAM + #pragma multi_compile __ UNITY_COLORSPACE_GAMMA + #pragma multi_compile __ ENABLE_COLOR_GRADING + #pragma multi_compile __ ENABLE_EYE_ADAPTATION + #pragma multi_compile __ ENABLE_DITHERING + #pragma multi_compile __ ENABLE_USER_LUT + #pragma fragment frag_tcg + #define TONEMAPPING_REINHARD + #include "TonemappingColorGrading.cginc" + ENDCG + } + + // Tonemapping (Neutral Hejl/Habble) + Pass + { + CGPROGRAM + #pragma multi_compile __ UNITY_COLORSPACE_GAMMA + #pragma multi_compile __ ENABLE_COLOR_GRADING + #pragma multi_compile __ ENABLE_EYE_ADAPTATION + #pragma multi_compile __ ENABLE_DITHERING + #pragma multi_compile __ ENABLE_USER_LUT + #pragma fragment frag_tcg + #define TONEMAPPING_NEUTRAL + #include "TonemappingColorGrading.cginc" + ENDCG + } + + // Eye adaptation debug slider + Pass + { + CGPROGRAM + #pragma fragment frag_debug + #include "TonemappingColorGrading.cginc" + + half4 frag_debug(v2f_img i) : SV_Target + { + half lum = tex2D(_MainTex, i.uv).r; + half grey = i.uv.x; + + int lum_px = floor(256.0 * lum); + int g_px = floor(256.0 * grey); + + half3 color = half3(grey, grey, grey); + color = lerp(color, half3(1.0, 0.0, 0.0), lum_px == g_px); + + return half4(color, 1.0); + } + ENDCG + } + } +} diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/TonemappingColorGrading/Resources/TonemappingColorGrading.shader.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/TonemappingColorGrading/Resources/TonemappingColorGrading.shader.meta new file mode 100644 index 0000000..3ca5284 --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/TonemappingColorGrading/Resources/TonemappingColorGrading.shader.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 964b34bbab7f5e64fa40f37eaccac1ad +timeCreated: 1435513939 +licenseType: Store +ShaderImporter: + defaultTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/TonemappingColorGrading/TonemappingColorGrading.cs b/IronToad_UnityProject/Assets/Standard Assets/Effects/TonemappingColorGrading/TonemappingColorGrading.cs new file mode 100644 index 0000000..e387bd2 --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/TonemappingColorGrading/TonemappingColorGrading.cs @@ -0,0 +1,1044 @@ +namespace UnityStandardAssets.CinematicEffects +{ + using UnityEngine; + using UnityEngine.Events; + using System; + + [ExecuteInEditMode] + [RequireComponent(typeof(Camera))] + [AddComponentMenu("Image Effects/Cinematic/Tonemapping and Color Grading")] +#if UNITY_5_4_OR_NEWER + [ImageEffectAllowedInSceneView] +#endif + public class TonemappingColorGrading : MonoBehaviour + { +#if UNITY_EDITOR + // EDITOR ONLY call for allowing the editor to update the histogram + public UnityAction onFrameEndEditorOnly; + + [SerializeField] + private ComputeShader m_HistogramComputeShader; + public ComputeShader histogramComputeShader + { + get + { + if (m_HistogramComputeShader == null) + m_HistogramComputeShader = Resources.Load("HistogramCompute"); + + return m_HistogramComputeShader; + } + } + + [SerializeField] + private Shader m_HistogramShader; + public Shader histogramShader + { + get + { + if (m_HistogramShader == null) + m_HistogramShader = Shader.Find("Hidden/TonemappingColorGradingHistogram"); + + return m_HistogramShader; + } + } + + [SerializeField] + public bool histogramRefreshOnPlay = true; +#endif + + #region Attributes + [AttributeUsage(AttributeTargets.Field)] + public class SettingsGroup : Attribute + {} + + public class IndentedGroup : PropertyAttribute + {} + + public class ChannelMixer : PropertyAttribute + {} + + public class ColorWheelGroup : PropertyAttribute + { + public int minSizePerWheel = 60; + public int maxSizePerWheel = 150; + + public ColorWheelGroup() + {} + + public ColorWheelGroup(int minSizePerWheel, int maxSizePerWheel) + { + this.minSizePerWheel = minSizePerWheel; + this.maxSizePerWheel = maxSizePerWheel; + } + } + + public class Curve : PropertyAttribute + { + public Color color = Color.white; + + public Curve() + {} + + public Curve(float r, float g, float b, float a) // Can't pass a struct in an attribute + { + color = new Color(r, g, b, a); + } + } + #endregion + + #region Settings + [Serializable] + public struct EyeAdaptationSettings + { + public bool enabled; + + [Min(0f), Tooltip("Midpoint Adjustment.")] + public float middleGrey; + + [Tooltip("The lowest possible exposure value; adjust this value to modify the brightest areas of your level.")] + public float min; + + [Tooltip("The highest possible exposure value; adjust this value to modify the darkest areas of your level.")] + public float max; + + [Min(0f), Tooltip("Speed of linear adaptation. Higher is faster.")] + public float speed; + + [Tooltip("Displays a luminosity helper in the GameView.")] + public bool showDebug; + + public static EyeAdaptationSettings defaultSettings + { + get + { + return new EyeAdaptationSettings + { + enabled = false, + showDebug = false, + middleGrey = 0.5f, + min = -3f, + max = 3f, + speed = 1.5f + }; + } + } + } + + public enum Tonemapper + { + ACES, + Curve, + Hable, + HejlDawson, + Photographic, + Reinhard, + Neutral + } + + [Serializable] + public struct TonemappingSettings + { + public bool enabled; + + [Tooltip("Tonemapping technique to use. ACES is the recommended one.")] + public Tonemapper tonemapper; + + [Min(0f), Tooltip("Adjusts the overall exposure of the scene.")] + public float exposure; + + [Tooltip("Custom tonemapping curve.")] + public AnimationCurve curve; + + // Neutral settings + [Range(-0.1f, 0.1f)] + public float neutralBlackIn; + + [Range(1f, 20f)] + public float neutralWhiteIn; + + [Range(-0.09f, 0.1f)] + public float neutralBlackOut; + + [Range(1f, 19f)] + public float neutralWhiteOut; + + [Range(0.1f, 20f)] + public float neutralWhiteLevel; + + [Range(1f, 10f)] + public float neutralWhiteClip; + + public static TonemappingSettings defaultSettings + { + get + { + return new TonemappingSettings + { + enabled = false, + tonemapper = Tonemapper.Neutral, + exposure = 1f, + curve = CurvesSettings.defaultCurve, + neutralBlackIn = 0.02f, + neutralWhiteIn = 10f, + neutralBlackOut = 0f, + neutralWhiteOut = 10f, + neutralWhiteLevel = 5.3f, + neutralWhiteClip = 10f + }; + } + } + } + + [Serializable] + public struct LUTSettings + { + public bool enabled; + + [Tooltip("Custom lookup texture (strip format, e.g. 256x16).")] + public Texture texture; + + [Range(0f, 1f), Tooltip("Blending factor.")] + public float contribution; + + public static LUTSettings defaultSettings + { + get + { + return new LUTSettings + { + enabled = false, + texture = null, + contribution = 1f + }; + } + } + } + + [Serializable] + public struct ColorWheelsSettings + { + [ColorUsage(false)] + public Color shadows; + + [ColorUsage(false)] + public Color midtones; + + [ColorUsage(false)] + public Color highlights; + + public static ColorWheelsSettings defaultSettings + { + get + { + return new ColorWheelsSettings + { + shadows = Color.white, + midtones = Color.white, + highlights = Color.white + }; + } + } + } + + [Serializable] + public struct BasicsSettings + { + [Range(-2f, 2f), Tooltip("Sets the white balance to a custom color temperature.")] + public float temperatureShift; + + [Range(-2f, 2f), Tooltip("Sets the white balance to compensate for a green or magenta tint.")] + public float tint; + + [Space, Range(-0.5f, 0.5f), Tooltip("Shift the hue of all colors.")] + public float hue; + + [Range(0f, 2f), Tooltip("Pushes the intensity of all colors.")] + public float saturation; + + [Range(-1f, 1f), Tooltip("Adjusts the saturation so that clipping is minimized as colors approach full saturation.")] + public float vibrance; + + [Range(0f, 10f), Tooltip("Brightens or darkens all colors.")] + public float value; + + [Space, Range(0f, 2f), Tooltip("Expands or shrinks the overall range of tonal values.")] + public float contrast; + + [Range(0.01f, 5f), Tooltip("Contrast gain curve. Controls the steepness of the curve.")] + public float gain; + + [Range(0.01f, 5f), Tooltip("Applies a pow function to the source.")] + public float gamma; + + public static BasicsSettings defaultSettings + { + get + { + return new BasicsSettings + { + temperatureShift = 0f, + tint = 0f, + contrast = 1f, + hue = 0f, + saturation = 1f, + value = 1f, + vibrance = 0f, + gain = 1f, + gamma = 1f + }; + } + } + } + + [Serializable] + public struct ChannelMixerSettings + { + public int currentChannel; + public Vector3[] channels; + + public static ChannelMixerSettings defaultSettings + { + get + { + return new ChannelMixerSettings + { + currentChannel = 0, + channels = new[] + { + new Vector3(1f, 0f, 0f), + new Vector3(0f, 1f, 0f), + new Vector3(0f, 0f, 1f) + } + }; + } + } + } + + [Serializable] + public struct CurvesSettings + { + [Curve] + public AnimationCurve master; + + [Curve(1f, 0f, 0f, 1f)] + public AnimationCurve red; + + [Curve(0f, 1f, 0f, 1f)] + public AnimationCurve green; + + [Curve(0f, 1f, 1f, 1f)] + public AnimationCurve blue; + + public static CurvesSettings defaultSettings + { + get + { + return new CurvesSettings + { + master = defaultCurve, + red = defaultCurve, + green = defaultCurve, + blue = defaultCurve + }; + } + } + + public static AnimationCurve defaultCurve + { + get { return new AnimationCurve(new Keyframe(0f, 0f, 1f, 1f), new Keyframe(1f, 1f, 1f, 1f)); } + } + } + + public enum ColorGradingPrecision + { + Normal = 16, + High = 32 + } + + [Serializable] + public struct ColorGradingSettings + { + public bool enabled; + + [Tooltip("Internal LUT precision. \"Normal\" is 256x16, \"High\" is 1024x32. Prefer \"Normal\" on mobile devices.")] + public ColorGradingPrecision precision; + + [Space, ColorWheelGroup] + public ColorWheelsSettings colorWheels; + + [Space, IndentedGroup] + public BasicsSettings basics; + + [Space, ChannelMixer] + public ChannelMixerSettings channelMixer; + + [Space, IndentedGroup] + public CurvesSettings curves; + + [Space, Tooltip("Use dithering to try and minimize color banding in dark areas.")] + public bool useDithering; + + [Tooltip("Displays the generated LUT in the top left corner of the GameView.")] + public bool showDebug; + + public static ColorGradingSettings defaultSettings + { + get + { + return new ColorGradingSettings + { + enabled = false, + useDithering = false, + showDebug = false, + precision = ColorGradingPrecision.Normal, + colorWheels = ColorWheelsSettings.defaultSettings, + basics = BasicsSettings.defaultSettings, + channelMixer = ChannelMixerSettings.defaultSettings, + curves = CurvesSettings.defaultSettings + }; + } + } + + internal void Reset() + { + curves = CurvesSettings.defaultSettings; + } + } + + [SerializeField, SettingsGroup] + private EyeAdaptationSettings m_EyeAdaptation = EyeAdaptationSettings.defaultSettings; + public EyeAdaptationSettings eyeAdaptation + { + get { return m_EyeAdaptation; } + set { m_EyeAdaptation = value; } + } + + [SerializeField, SettingsGroup] + private TonemappingSettings m_Tonemapping = TonemappingSettings.defaultSettings; + public TonemappingSettings tonemapping + { + get { return m_Tonemapping; } + set + { + m_Tonemapping = value; + SetTonemapperDirty(); + } + } + + [SerializeField, SettingsGroup] + private ColorGradingSettings m_ColorGrading = ColorGradingSettings.defaultSettings; + public ColorGradingSettings colorGrading + { + get { return m_ColorGrading; } + set + { + m_ColorGrading = value; + SetDirty(); + } + } + + [SerializeField, SettingsGroup] + private LUTSettings m_Lut = LUTSettings.defaultSettings; + public LUTSettings lut + { + get { return m_Lut; } + set { m_Lut = value; } + } + #endregion + + private Texture2D m_IdentityLut; + private RenderTexture m_InternalLut; + private Texture2D m_CurveTexture; + private Texture2D m_TonemapperCurve; + private float m_TonemapperCurveRange; + + private Texture2D identityLut + { + get + { + if (m_IdentityLut == null || m_IdentityLut.height != lutSize) + { + DestroyImmediate(m_IdentityLut); + m_IdentityLut = GenerateIdentityLut(lutSize); + } + + return m_IdentityLut; + } + } + + private RenderTexture internalLutRt + { + get + { + if (m_InternalLut == null || !m_InternalLut.IsCreated() || m_InternalLut.height != lutSize) + { + DestroyImmediate(m_InternalLut); + m_InternalLut = new RenderTexture(lutSize * lutSize, lutSize, 0, RenderTextureFormat.ARGB32) + { + name = "Internal LUT", + filterMode = FilterMode.Bilinear, + anisoLevel = 0, + hideFlags = HideFlags.DontSave + }; + } + + return m_InternalLut; + } + } + + private Texture2D curveTexture + { + get + { + if (m_CurveTexture == null) + { + m_CurveTexture = new Texture2D(256, 1, TextureFormat.ARGB32, false, true) + { + name = "Curve texture", + wrapMode = TextureWrapMode.Clamp, + filterMode = FilterMode.Bilinear, + anisoLevel = 0, + hideFlags = HideFlags.DontSave + }; + } + + return m_CurveTexture; + } + } + + private Texture2D tonemapperCurve + { + get + { + if (m_TonemapperCurve == null) + { + TextureFormat format = TextureFormat.RGB24; + if (SystemInfo.SupportsTextureFormat(TextureFormat.RFloat)) + format = TextureFormat.RFloat; + else if (SystemInfo.SupportsTextureFormat(TextureFormat.RHalf)) + format = TextureFormat.RHalf; + + m_TonemapperCurve = new Texture2D(256, 1, format, false, true) + { + name = "Tonemapper curve texture", + wrapMode = TextureWrapMode.Clamp, + filterMode = FilterMode.Bilinear, + anisoLevel = 0, + hideFlags = HideFlags.DontSave + }; + } + + return m_TonemapperCurve; + } + } + + [SerializeField] + private Shader m_Shader; + public Shader shader + { + get + { + if (m_Shader == null) + m_Shader = Shader.Find("Hidden/TonemappingColorGrading"); + + return m_Shader; + } + } + + private Material m_Material; + public Material material + { + get + { + if (m_Material == null) + m_Material = ImageEffectHelper.CheckShaderAndCreateMaterial(shader); + + return m_Material; + } + } + + public bool isGammaColorSpace + { + get { return QualitySettings.activeColorSpace == ColorSpace.Gamma; } + } + + public int lutSize + { + get { return (int)colorGrading.precision; } + } + + private enum Pass + { + LutGen, + AdaptationLog, + AdaptationExpBlend, + AdaptationExp, + TonemappingOff, + TonemappingACES, + TonemappingCurve, + TonemappingHable, + TonemappingHejlDawson, + TonemappingPhotographic, + TonemappingReinhard, + TonemappingNeutral, + AdaptationDebug + } + + public bool validRenderTextureFormat { get; private set; } + public bool validUserLutSize { get; private set; } + + private bool m_Dirty = true; + private bool m_TonemapperDirty = true; + + private RenderTexture m_SmallAdaptiveRt; + private RenderTextureFormat m_AdaptiveRtFormat; + + public void SetDirty() + { + m_Dirty = true; + } + + public void SetTonemapperDirty() + { + m_TonemapperDirty = true; + } + + private void OnEnable() + { + if (!ImageEffectHelper.IsSupported(shader, false, true, this)) + { + enabled = false; + return; + } + + SetDirty(); + SetTonemapperDirty(); + } + + private void OnDisable() + { + if (m_Material != null) + DestroyImmediate(m_Material); + + if (m_IdentityLut != null) + DestroyImmediate(m_IdentityLut); + + if (m_InternalLut != null) + DestroyImmediate(internalLutRt); + + if (m_SmallAdaptiveRt != null) + DestroyImmediate(m_SmallAdaptiveRt); + + if (m_CurveTexture != null) + DestroyImmediate(m_CurveTexture); + + if (m_TonemapperCurve != null) + DestroyImmediate(m_TonemapperCurve); + + m_Material = null; + m_IdentityLut = null; + m_InternalLut = null; + m_SmallAdaptiveRt = null; + m_CurveTexture = null; + m_TonemapperCurve = null; + } + + private void OnValidate() + { + SetDirty(); + SetTonemapperDirty(); + } + + private static Texture2D GenerateIdentityLut(int dim) + { + Color[] newC = new Color[dim * dim * dim]; + float oneOverDim = 1f / ((float)dim - 1f); + + for (int i = 0; i < dim; i++) + for (int j = 0; j < dim; j++) + for (int k = 0; k < dim; k++) + newC[i + (j * dim) + (k * dim * dim)] = new Color((float)i * oneOverDim, Mathf.Abs((float)k * oneOverDim), (float)j * oneOverDim, 1f); + + Texture2D tex2D = new Texture2D(dim * dim, dim, TextureFormat.RGB24, false, true) + { + name = "Identity LUT", + filterMode = FilterMode.Bilinear, + anisoLevel = 0, + hideFlags = HideFlags.DontSave + }; + tex2D.SetPixels(newC); + tex2D.Apply(); + + return tex2D; + } + + // An analytical model of chromaticity of the standard illuminant, by Judd et al. + // http://en.wikipedia.org/wiki/Standard_illuminant#Illuminant_series_D + // Slightly modifed to adjust it with the D65 white point (x=0.31271, y=0.32902). + private float StandardIlluminantY(float x) + { + return 2.87f * x - 3f * x * x - 0.27509507f; + } + + // CIE xy chromaticity to CAT02 LMS. + // http://en.wikipedia.org/wiki/LMS_color_space#CAT02 + private 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); + } + + private Vector3 GetWhiteBalance() + { + float t1 = colorGrading.basics.temperatureShift; + float t2 = colorGrading.basics.tint; + + // 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. + Vector3 w1 = new Vector3(0.949237f, 1.03542f, 1.08728f); // D65 white point + Vector3 w2 = CIExyToLMS(x, y); + return new Vector3(w1.x / w2.x, w1.y / w2.y, w1.z / w2.z); + } + + private static Color NormalizeColor(Color c) + { + float sum = (c.r + c.g + c.b) / 3f; + + if (Mathf.Approximately(sum, 0f)) + return new Color(1f, 1f, 1f, 1f); + + return new Color + { + r = c.r / sum, + g = c.g / sum, + b = c.b / sum, + a = 1f + }; + } + + private void GenerateLiftGammaGain(out Color lift, out Color gamma, out Color gain) + { + Color nLift = NormalizeColor(colorGrading.colorWheels.shadows); + Color nGamma = NormalizeColor(colorGrading.colorWheels.midtones); + Color nGain = NormalizeColor(colorGrading.colorWheels.highlights); + + float avgLift = (nLift.r + nLift.g + nLift.b) / 3f; + float avgGamma = (nGamma.r + nGamma.g + nGamma.b) / 3f; + float avgGain = (nGain.r + nGain.g + nGain.b) / 3f; + + // Magic numbers + const float liftScale = 0.1f; + const float gammaScale = 0.5f; + const float gainScale = 0.5f; + + float liftR = (nLift.r - avgLift) * liftScale; + float liftG = (nLift.g - avgLift) * liftScale; + float liftB = (nLift.b - avgLift) * liftScale; + + float gammaR = Mathf.Pow(2f, (nGamma.r - avgGamma) * gammaScale); + float gammaG = Mathf.Pow(2f, (nGamma.g - avgGamma) * gammaScale); + float gammaB = Mathf.Pow(2f, (nGamma.b - avgGamma) * gammaScale); + + float gainR = Mathf.Pow(2f, (nGain.r - avgGain) * gainScale); + float gainG = Mathf.Pow(2f, (nGain.g - avgGain) * gainScale); + float gainB = Mathf.Pow(2f, (nGain.b - avgGain) * gainScale); + + const float minGamma = 0.01f; + float invGammaR = 1f / Mathf.Max(minGamma, gammaR); + float invGammaG = 1f / Mathf.Max(minGamma, gammaG); + float invGammaB = 1f / Mathf.Max(minGamma, gammaB); + + lift = new Color(liftR, liftG, liftB); + gamma = new Color(invGammaR, invGammaG, invGammaB); + gain = new Color(gainR, gainG, gainB); + } + + private void GenCurveTexture() + { + AnimationCurve master = colorGrading.curves.master; + AnimationCurve red = colorGrading.curves.red; + AnimationCurve green = colorGrading.curves.green; + AnimationCurve blue = colorGrading.curves.blue; + + Color[] pixels = new Color[256]; + + for (float i = 0f; i <= 1f; i += 1f / 255f) + { + float m = Mathf.Clamp(master.Evaluate(i), 0f, 1f); + float r = Mathf.Clamp(red.Evaluate(i), 0f, 1f); + float g = Mathf.Clamp(green.Evaluate(i), 0f, 1f); + float b = Mathf.Clamp(blue.Evaluate(i), 0f, 1f); + pixels[(int)Mathf.Floor(i * 255f)] = new Color(r, g, b, m); + } + + curveTexture.SetPixels(pixels); + curveTexture.Apply(); + } + + private bool CheckUserLut() + { + validUserLutSize = (lut.texture.height == (int)Mathf.Sqrt(lut.texture.width)); + return validUserLutSize; + } + + private bool CheckSmallAdaptiveRt() + { + if (m_SmallAdaptiveRt != null) + return false; + + m_AdaptiveRtFormat = RenderTextureFormat.ARGBHalf; + + if (SystemInfo.SupportsRenderTextureFormat(RenderTextureFormat.RGHalf)) + m_AdaptiveRtFormat = RenderTextureFormat.RGHalf; + + m_SmallAdaptiveRt = new RenderTexture(1, 1, 0, m_AdaptiveRtFormat); + m_SmallAdaptiveRt.hideFlags = HideFlags.DontSave; + + return true; + } + + private void OnGUI() + { + if (Event.current.type != EventType.Repaint) + return; + + int yoffset = 0; + + // Color grading debug + if (m_InternalLut != null && colorGrading.enabled && colorGrading.showDebug) + { + Graphics.DrawTexture(new Rect(0f, yoffset, lutSize * lutSize, lutSize), internalLutRt); + yoffset += lutSize; + } + + // Eye Adaptation debug + if (m_SmallAdaptiveRt != null && eyeAdaptation.enabled && eyeAdaptation.showDebug) + { + m_Material.SetPass((int)Pass.AdaptationDebug); + Graphics.DrawTexture(new Rect(0f, yoffset, 256, 16), m_SmallAdaptiveRt, m_Material); + } + } + + [ImageEffectTransformsToLDR] + private void OnRenderImage(RenderTexture source, RenderTexture destination) + { +#if UNITY_EDITOR + validRenderTextureFormat = true; + + if (source.format != RenderTextureFormat.ARGBHalf && source.format != RenderTextureFormat.ARGBFloat) + validRenderTextureFormat = false; +#endif + + material.shaderKeywords = null; + + RenderTexture rtSquared = null; + RenderTexture[] rts = null; + + if (eyeAdaptation.enabled) + { + bool freshlyBrewedSmallRt = CheckSmallAdaptiveRt(); + int srcSize = source.width < source.height ? source.width : source.height; + + // Fast lower or equal power of 2 + int adaptiveSize = srcSize; + adaptiveSize |= (adaptiveSize >> 1); + adaptiveSize |= (adaptiveSize >> 2); + adaptiveSize |= (adaptiveSize >> 4); + adaptiveSize |= (adaptiveSize >> 8); + adaptiveSize |= (adaptiveSize >> 16); + adaptiveSize -= (adaptiveSize >> 1); + + rtSquared = RenderTexture.GetTemporary(adaptiveSize, adaptiveSize, 0, m_AdaptiveRtFormat); + Graphics.Blit(source, rtSquared); + + int downsample = (int)Mathf.Log(rtSquared.width, 2f); + + int div = 2; + rts = new RenderTexture[downsample]; + for (int i = 0; i < downsample; i++) + { + rts[i] = RenderTexture.GetTemporary(rtSquared.width / div, rtSquared.width / div, 0, m_AdaptiveRtFormat); + div <<= 1; + } + + // Downsample pyramid + var lumRt = rts[downsample - 1]; + Graphics.Blit(rtSquared, rts[0], material, (int)Pass.AdaptationLog); + for (int i = 0; i < downsample - 1; i++) + { + Graphics.Blit(rts[i], rts[i + 1]); + lumRt = rts[i + 1]; + } + + // Keeping luminance values between frames, RT restore expected + m_SmallAdaptiveRt.MarkRestoreExpected(); + + material.SetFloat("_AdaptationSpeed", Mathf.Max(eyeAdaptation.speed, 0.001f)); + +#if UNITY_EDITOR + if (Application.isPlaying && !freshlyBrewedSmallRt) + Graphics.Blit(lumRt, m_SmallAdaptiveRt, material, (int)Pass.AdaptationExpBlend); + else + Graphics.Blit(lumRt, m_SmallAdaptiveRt, material, (int)Pass.AdaptationExp); +#else + Graphics.Blit(lumRt, m_SmallAdaptiveRt, material, freshlyBrewedSmallRt ? (int)Pass.AdaptationExp : (int)Pass.AdaptationExpBlend); +#endif + + material.SetFloat("_MiddleGrey", eyeAdaptation.middleGrey); + material.SetFloat("_AdaptationMin", Mathf.Pow(2f, eyeAdaptation.min)); + material.SetFloat("_AdaptationMax", Mathf.Pow(2f, eyeAdaptation.max)); + material.SetTexture("_LumTex", m_SmallAdaptiveRt); + material.EnableKeyword("ENABLE_EYE_ADAPTATION"); + } + + int renderPass = (int)Pass.TonemappingOff; + + if (tonemapping.enabled) + { + if (tonemapping.tonemapper == Tonemapper.Curve) + { + if (m_TonemapperDirty) + { + float range = 1f; + + if (tonemapping.curve.length > 0) + { + range = tonemapping.curve[tonemapping.curve.length - 1].time; + + for (float i = 0f; i <= 1f; i += 1f / 255f) + { + float c = tonemapping.curve.Evaluate(i * range); + tonemapperCurve.SetPixel(Mathf.FloorToInt(i * 255f), 0, new Color(c, c, c)); + } + + tonemapperCurve.Apply(); + } + + m_TonemapperCurveRange = 1f / range; + m_TonemapperDirty = false; + } + + material.SetFloat("_ToneCurveRange", m_TonemapperCurveRange); + material.SetTexture("_ToneCurve", tonemapperCurve); + } + else if (tonemapping.tonemapper == Tonemapper.Neutral) + { + const float scaleFactor = 20f; + const float scaleFactorHalf = scaleFactor * 0.5f; + + float inBlack = tonemapping.neutralBlackIn * scaleFactor + 1f; + float outBlack = tonemapping.neutralBlackOut * scaleFactorHalf + 1f; + float inWhite = tonemapping.neutralWhiteIn / scaleFactor; + float outWhite = 1f - tonemapping.neutralWhiteOut / scaleFactor; + float blackRatio = inBlack / outBlack; + float whiteRatio = inWhite / outWhite; + + const float a = 0.2f; + float b = Mathf.Max(0f, Mathf.LerpUnclamped(0.57f, 0.37f, blackRatio)); + float c = Mathf.LerpUnclamped(0.01f, 0.24f, whiteRatio); + float d = Mathf.Max(0f, Mathf.LerpUnclamped(0.02f, 0.20f, blackRatio)); + const float e = 0.02f; + const float f = 0.30f; + + material.SetVector("_NeutralTonemapperParams1", new Vector4(a, b, c, d)); + material.SetVector("_NeutralTonemapperParams2", new Vector4(e, f, tonemapping.neutralWhiteLevel, tonemapping.neutralWhiteClip / scaleFactorHalf)); + } + + material.SetFloat("_Exposure", tonemapping.exposure); + renderPass += (int)tonemapping.tonemapper + 1; + } + + if (colorGrading.enabled) + { + if (m_Dirty || !m_InternalLut.IsCreated()) + { + Color lift, gamma, gain; + GenerateLiftGammaGain(out lift, out gamma, out gain); + GenCurveTexture(); + + material.SetVector("_WhiteBalance", GetWhiteBalance()); + material.SetVector("_Lift", lift); + material.SetVector("_Gamma", gamma); + material.SetVector("_Gain", gain); + material.SetVector("_ContrastGainGamma", new Vector3(colorGrading.basics.contrast, colorGrading.basics.gain, 1f / colorGrading.basics.gamma)); + material.SetFloat("_Vibrance", colorGrading.basics.vibrance); + material.SetVector("_HSV", new Vector4(colorGrading.basics.hue, colorGrading.basics.saturation, colorGrading.basics.value)); + material.SetVector("_ChannelMixerRed", colorGrading.channelMixer.channels[0]); + material.SetVector("_ChannelMixerGreen", colorGrading.channelMixer.channels[1]); + material.SetVector("_ChannelMixerBlue", colorGrading.channelMixer.channels[2]); + material.SetTexture("_CurveTex", curveTexture); + internalLutRt.MarkRestoreExpected(); + Graphics.Blit(identityLut, internalLutRt, material, (int)Pass.LutGen); + m_Dirty = false; + } + + material.EnableKeyword("ENABLE_COLOR_GRADING"); + + if (colorGrading.useDithering) + material.EnableKeyword("ENABLE_DITHERING"); + + material.SetTexture("_InternalLutTex", internalLutRt); + material.SetVector("_InternalLutParams", new Vector3(1f / internalLutRt.width, 1f / internalLutRt.height, internalLutRt.height - 1f)); + } + + if (lut.enabled && lut.texture != null && CheckUserLut()) + { + material.SetTexture("_UserLutTex", lut.texture); + material.SetVector("_UserLutParams", new Vector4(1f / lut.texture.width, 1f / lut.texture.height, lut.texture.height - 1f, lut.contribution)); + material.EnableKeyword("ENABLE_USER_LUT"); + } + + Graphics.Blit(source, destination, material, renderPass); + + // Cleanup for eye adaptation + if (eyeAdaptation.enabled) + { + for (int i = 0; i < rts.Length; i++) + RenderTexture.ReleaseTemporary(rts[i]); + + RenderTexture.ReleaseTemporary(rtSquared); + } + +#if UNITY_EDITOR + // If we have an on frame end callabck we need to pass a valid result texture + // if destination is null we wrote to the backbuffer so we need to copy that out. + // It's slow and not amazing, but editor only + if (onFrameEndEditorOnly != null) + { + if (destination == null) + { + RenderTexture rt = RenderTexture.GetTemporary(source.width, source.height, 0); + Graphics.Blit(source, rt, material, renderPass); + onFrameEndEditorOnly(rt); + RenderTexture.ReleaseTemporary(rt); + RenderTexture.active = null; + } + else + { + onFrameEndEditorOnly(destination); + } + } +#endif + } + + public Texture2D BakeLUT() + { + Texture2D lut = new Texture2D(internalLutRt.width, internalLutRt.height, TextureFormat.RGB24, false, true); + RenderTexture.active = internalLutRt; + lut.ReadPixels(new Rect(0f, 0f, lut.width, lut.height), 0, 0); + RenderTexture.active = null; + return lut; + } + } +} diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/TonemappingColorGrading/TonemappingColorGrading.cs.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/TonemappingColorGrading/TonemappingColorGrading.cs.meta new file mode 100644 index 0000000..7885e24 --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/TonemappingColorGrading/TonemappingColorGrading.cs.meta @@ -0,0 +1,16 @@ +fileFormatVersion: 2 +guid: 58a7625302996c94ba07a8ca3351f668 +timeCreated: 1453901501 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: + - m_HistogramComputeShader: {fileID: 7200000, guid: 5ee4b74fa28a3e74e89423dd49705fc5, + type: 3} + - m_HistogramShader: {fileID: 4800000, guid: 9a8e838691462194482a43a02e424876, type: 3} + - m_Shader: {fileID: 4800000, guid: 964b34bbab7f5e64fa40f37eaccac1ad, type: 3} + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/_Scenes/LighthouseTestScene.unity b/IronToad_UnityProject/Assets/_Scenes/LighthouseTestScene.unity index a971ab3ea1f3c6f04a693d15a94989d6effd3668..67939e2f993835fca0baef9eb2640218d04c7fa8 100644 GIT binary patch delta 8122 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 M_M>;n`?=x&0biLs0RR91 delta 4413 zcmYkA2~?Cv634r^90X)W1co)rF%Z!x;(_87K{UD|I;@GHF$5Ac7%$XCF&-lx2x=mU zN26IHsM+B4g3fa%huO@GYaodl;*k*JM#N{HyYVHg#ut-ab^rZMef#aa*HhKM?ysu4 zy1KuCTmKH~d@m?LPK3p3}5w3^;de_f+!P_^)CI;vo7#XjRNik|HU>QJyS>nS?N5XbTTj^%VkG1f%sE*=B_hO<=m&Czz%8 zGtBm9)(*D7PlzsfW&kt$0K-QLv%(b3heLDnQ@lM!IjI6%0;yu}WF`g*QH#Ec{a?&# z!BP=)IM^L#EvZJ(A6M@E9fm|FSQ(_U=Vn$iNQg%C&1jy=fxe06!9u8A4?)|#pjd5~ zSO=!BSTZxo%qS$SX^0S^yvRK~F#Vtx-I;>K zqmF-XY|{(O?t|&|@glRD$wqw?GjnGf+azE54PgjzE8AfhtYug@#W1*s*?lnmlDx(!fUuLkK&Vp8gVMtza857KJvCS^hL3^3jimfAKQICO~~ZXZ%nJmqNtZjR5nQ z)q?3O&S#dIYXmrxS>Ydy0C#+{6k*_60;_;jncfMe{0sARL=I_1+r<+L!Bj9YXuFxU zf+0qsE+ok;?r9;~(O0$bWZf0az~>obJI66A1=9;Sir5aJM| zif}!%n(J(lI zSyi!NFmUr<;Sw)Vu(#P@5VQO_csKbA(F?o_GwVE~s7=hOz^X6@?lbE%E9YkLh>(#jF zYW=uWu$fi>8(O;tv6sve!LBoF0;@$o39Yqm-&_bW=@lXBAeECZncV`z-6bAJyTB}U zmG7m~2kauV7BD;fYrjt}F|@As6L{u=)>q8jU>WG+CyJOnC~6^u5NnLP zBAZz`mY16=87paERu87` zk0;RfGwTFX?-I3;1I&^ujD;NZF^8xHtih!IXgQl-!0sZD_1a=I$5WX#g0)~wtz;Ur z(hbHPU}sjp(KxbOdnK+=_S(So>fgr9zDZ>UD^vzwWq1ovzvo|LX5DOL<`bJ&GnfIU z-vQ0c++cdDTbSje%*{x(2|hk$R#I))%Xi#}N4X#afJ-1%s%J7YZ7~eaVpb2P2ly)1u84E!_$D`I;w%nG+*8^Kf^MWP`tAs58cM$^z^vp&P$29MRZ zFg7KDtkhlZN}#7?nT`6(E;fpi4eDzMy5?_Uz8`3prKM!o#$1P1($@ql z6|3l3KOf3nry*^ot9U(~4ML!Uswo=tBw~-1C0l46?0z|kqIYk_RzxRJg6!Ok;Gfz` z9eSXy(l@BZFQf}HHf~~8+0x~6_Fh$eKe4AWW_#;cAS|1Rc1%z!YrIC?>C>;WcCg&)AY{f$jockR%^QZ>x8inves+5 zeZBA;_+^u(hc<8YoUf?X^vvEZo|132`S`s6@9cZqHT~}QiQe63-_Z0mf64OFj9r@k zOj?n*x=IFV9h>Y`Pw$XTo~frd>AEaxAX`k#gTbe-WzY4f$Yxp6PS4M4)AR^g*Fes& zGhXxQ7mvoCR>Obk(cun81;<9)5+8j*}pMJ*c89YPN zf3uzRX74M|^yV&aduPd$`zhAZLoV=|OIK^SBWs%1KD|QItH%uS4vXKY>7gH6y=V7U zYWiY-;Z1zMO4CcXUhw3WZPE106^A@?TDEF>WZ@>yvLo9xeQA1*XIu2En!Yo?r)Sl8 zpPqf{3wPn7SEp(N^7Sb9`JKLj;?CrZJeN;Db2uoo=CV%@*}f<<%!N2#u+V`RlSk~mKjWVa@I=$rm+ka{_N*GF2CsGqDkjz?`LC{5Pxfy4SqC|NL* ztT}~;H

@9CB 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�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