From e178933780a5516695fc97d9775bed43bad07ce9 Mon Sep 17 00:00:00 2001 From: "Alex.Kirel" Date: Fri, 28 Jul 2023 13:34:02 +0500 Subject: [PATCH] Added Cinematic Effects, QuickRopes 2, removed unresolved dependencies. --- .../Cinematic Effects/AmbientOcclusion.meta | 9 + .../AmbientOcclusion/AmbientOcclusion.cs | 347 ++++ .../AmbientOcclusion/AmbientOcclusion.cs.meta | 14 + .../AmbientOcclusion/Editor.meta | 9 + .../Editor/AmbientOcclusionEditor.cs | 63 + .../Editor/AmbientOcclusionEditor.cs.meta | 12 + .../AmbientOcclusion/Helpers.meta | 9 + .../Helpers/PropertyObserver.cs | 38 + .../Helpers/PropertyObserver.cs.meta | 12 + .../AmbientOcclusion/Helpers/Settings.cs | 71 + .../AmbientOcclusion/Helpers/Settings.cs.meta | 12 + .../AmbientOcclusion/Resources.meta | 9 + .../Resources/AmbientOcclusion.shader | 476 +++++ .../Resources/AmbientOcclusion.shader.meta | 9 + Assets/Cinematic Effects/Bloom.meta | 9 + Assets/Cinematic Effects/Bloom/Bloom.cs | 223 +++ Assets/Cinematic Effects/Bloom/Bloom.cs.meta | 13 + Assets/Cinematic Effects/Bloom/Editor.meta | 9 + .../Bloom/Editor/BloomEditor.cs | 32 + .../Bloom/Editor/BloomEditor.cs.meta | 12 + Assets/Cinematic Effects/Bloom/Resources.meta | 9 + .../Bloom/Resources/Bloom.shader | 284 +++ .../Bloom/Resources/Bloom.shader.meta | 9 + Assets/Cinematic Effects/BloomBeta.meta | 9 + .../Cinematic Effects/BloomBeta/Editor.meta | 9 + .../BloomBeta/Editor/BokehTextureGenerator.cs | 526 ++++++ .../Editor/BokehTextureGenerator.cs.meta | 10 + .../BloomBeta/Editor/UltimateBloomEditor.cs | 445 +++++ .../Editor/UltimateBloomEditor.cs.meta | 10 + .../Cinematic Effects/BloomBeta/Graphics.meta | 9 + .../BloomBeta/Graphics/Bokeh.png | Bin 0 -> 5477 bytes .../BloomBeta/Graphics/Bokeh.png.meta | 53 + .../BloomBeta/Graphics/BokehRound.png | Bin 0 -> 6370 bytes .../BloomBeta/Graphics/BokehRound.png.meta | 53 + .../BloomBeta/Graphics/Bokehround2.png | Bin 0 -> 8242 bytes .../BloomBeta/Graphics/Bokehround2.png.meta | 53 + .../BloomBeta/Graphics/FlareMask.png | Bin 0 -> 6381 bytes .../BloomBeta/Graphics/FlareMask.png.meta | 53 + .../BloomBeta/Graphics/FlareMaterial.mat | 35 + .../BloomBeta/Graphics/FlareMaterial.mat.meta | 6 + .../BloomBeta/ImgForDirtGenerator.meta | 9 + .../ImgForDirtGenerator/BokehAlpha.png | Bin 0 -> 5720 bytes .../ImgForDirtGenerator/BokehAlpha.png.meta | 53 + .../ImgForDirtGenerator/BokehRoundAlpha1.png | Bin 0 -> 5119 bytes .../BokehRoundAlpha1.png.meta | 53 + .../ImgForDirtGenerator/BokehRoundAlpha2.png | Bin 0 -> 5898 bytes .../BokehRoundAlpha2.png.meta | 53 + .../BloomBeta/Resources.meta | 9 + .../BloomBeta/Resources/ShadersSimplified.zip | Bin 0 -> 20346 bytes .../Resources/ShadersSimplified.zip.meta | 8 + .../Resources/UltimateBloomBokehMisc.shader | 59 + .../UltimateBloomBokehMisc.shader.meta | 7 + .../Resources/UltimateBloomCombine.shader | 337 ++++ .../UltimateBloomCombine.shader.meta | 7 + .../Resources/UltimateBloomCombineCore.cginc | 147 ++ .../UltimateBloomCombineCore.cginc.meta | 7 + .../UltimateBloomCombineFlareDirt.shader | 342 ++++ .../UltimateBloomCombineFlareDirt.shader.meta | 7 + .../Resources/UltimateBloomMixer.shader | 108 ++ .../Resources/UltimateBloomMixer.shader.meta | 7 + .../Resources/UltimateBloomShader.shader | 488 +++++ .../Resources/UltimateBloomShader.shader.meta | 7 + .../Resources/UltimateBokehTexture.shader | 72 + .../UltimateBokehTexture.shader.meta | 7 + .../Resources/UltimateBrightpassCore.cginc | 44 + .../UltimateBrightpassCore.cginc.meta | 7 + .../Resources/UltimateBrightpassMask.shader | 131 ++ .../UltimateBrightpassMask.shader.meta | 7 + .../Resources/UltimateFlareCore.cginc | 95 + .../Resources/UltimateFlareCore.cginc.meta | 7 + .../Resources/UltimateFlareDouble.shader | 123 ++ .../Resources/UltimateFlareDouble.shader.meta | 7 + .../Resources/UltimateFlareMask.shader | 52 + .../Resources/UltimateFlareMask.shader.meta | 7 + .../Resources/UltimateFlareMeshShader.shader | 72 + .../UltimateFlareMeshShader.shader.meta | 7 + .../Resources/UltimateFlareSingle.shader | 121 ++ .../Resources/UltimateFlareSingle.shader.meta | 7 + .../Resources/UltimateSampling.shader | 751 ++++++++ .../Resources/UltimateSampling.shader.meta | 7 + .../Cinematic Effects/BloomBeta/Scripts.meta | 9 + .../BloomBeta/Scripts/BokehRenderer.cs | 191 ++ .../BloomBeta/Scripts/BokehRenderer.cs.meta | 10 + .../BloomBeta/Scripts/DeluxeFilmicCurve.cs | 241 +++ .../Scripts/DeluxeFilmicCurve.cs.meta | 10 + .../BloomBeta/Scripts/UBHelper.cs | 84 + .../BloomBeta/Scripts/UBHelper.cs.meta | 12 + .../BloomBeta/Scripts/UltimateBloom.cs | 1568 +++++++++++++++++ .../BloomBeta/Scripts/UltimateBloom.cs.meta | 10 + .../BloomBeta/UltimateBloomPathLocator.cs | 10 + .../UltimateBloomPathLocator.cs.meta | 12 + Assets/Cinematic Effects/Common.meta | 9 + Assets/Cinematic Effects/Common/Editor.meta | 9 + .../Common/Editor/EditorGUIHelper.cs | 62 + .../Common/Editor/EditorGUIHelper.cs.meta | 12 + .../Common/Editor/FieldFinder.cs | 25 + .../Common/Editor/FieldFinder.cs.meta | 12 + .../Common/Editor/MinDrawer.cs | 29 + .../Common/Editor/MinDrawer.cs.meta | 12 + .../Common/ImageEffectHelper.cs | 63 + .../Common/ImageEffectHelper.cs.meta | 12 + .../Cinematic Effects/Common/MinAttribute.cs | 14 + .../Common/MinAttribute.cs.meta | 12 + .../Common/RenderTextureUtility.cs | 44 + .../Common/RenderTextureUtility.cs.meta | 12 + Assets/Cinematic Effects/DepthOfField.meta | 9 + .../DepthOfField/DepthOfField.cs | 946 ++++++++++ .../DepthOfField/DepthOfField.cs.meta | 18 + .../DepthOfField/Editor.meta | 9 + .../DepthOfField/Editor/DepthOfFieldEditor.cs | 109 ++ .../Editor/DepthOfFieldEditor.cs.meta | 12 + .../DepthOfField/Helpers.meta | 9 + .../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 + .../DepthOfField/Resources.meta | 9 + .../Resources/BokehSplatting.shader | 227 +++ .../Resources/BokehSplatting.shader.meta | 9 + .../Resources/DepthOfField.shader | 1447 +++++++++++++++ .../Resources/DepthOfField.shader.meta | 9 + .../Resources/MedianFilter.shader | 160 ++ .../Resources/MedianFilter.shader.meta | 9 + Assets/Cinematic Effects/LensAberrations.meta | 9 + .../LensAberrations/Editor.meta | 9 + .../Editor/LensAberrationsEditor.cs | 102 ++ .../Editor/LensAberrationsEditor.cs.meta | 12 + .../LensAberrations/LensAberrations.cs | 328 ++++ .../LensAberrations/LensAberrations.cs.meta | 13 + .../LensAberrations/Resources.meta | 9 + .../Resources/LensAberrations.shader | 299 ++++ .../Resources/LensAberrations.shader.meta | 9 + Assets/Cinematic Effects/MotionBlur.meta | 9 + .../Cinematic Effects/MotionBlur/Plugins.meta | 9 + .../MotionBlur/Plugins/AmplifyMotion.dll | Bin 0 -> 3584 bytes .../MotionBlur/Plugins/AmplifyMotion.dll.meta | 22 + .../MotionBlur/Plugins/AmplifyMotionBase.cs | 1167 ++++++++++++ .../Plugins/AmplifyMotionBase.cs.meta | 10 + .../MotionBlur/Plugins/AmplifyMotionCamera.cs | 318 ++++ .../Plugins/AmplifyMotionCamera.cs.meta | 10 + .../MotionBlur/Plugins/AmplifyMotionEffect.cs | 13 + .../Plugins/AmplifyMotionEffect.cs.meta | 10 + .../MotionBlur/Plugins/AmplifyMotionObject.cs | 10 + .../Plugins/AmplifyMotionObject.cs.meta | 10 + .../Plugins/AmplifyMotionObjectBase.cs | 371 ++++ .../Plugins/AmplifyMotionObjectBase.cs.meta | 10 + .../Plugins/AmplifyMotionPostProcess.cs | 20 + .../Plugins/AmplifyMotionPostProcess.cs.meta | 10 + .../MotionBlur/Plugins/ClothState.cs | 293 +++ .../MotionBlur/Plugins/ClothState.cs.meta | 10 + .../MotionBlur/Plugins/Editor.meta | 9 + .../MotionBlur/Plugins/Editor/About.cs | 92 + .../MotionBlur/Plugins/Editor/About.cs.meta | 10 + .../Plugins/Editor/AmplifyMotionEditor.dll | Bin 0 -> 3584 bytes .../Editor/AmplifyMotionEditor.dll.meta | 22 + .../Editor/AmplifyMotionObjectEditor.cs | 14 + .../Editor/AmplifyMotionObjectEditor.cs.meta | 10 + .../Editor/AmplifyMotionObjectEditorBase.cs | 13 + .../AmplifyMotionObjectEditorBase.cs.meta | 10 + .../MotionBlur/Plugins/Editor/Resources.meta | 9 + .../Plugins/Editor/Resources/effect-icon.png | Bin 0 -> 3586 bytes .../Editor/Resources/effect-icon.png.meta | 55 + .../Plugins/Editor/Resources/object-icon.tif | Bin 0 -> 40236 bytes .../Editor/Resources/object-icon.tif.meta | 55 + .../MotionBlur/Plugins/ParticleState.cs | 327 ++++ .../MotionBlur/Plugins/ParticleState.cs.meta | 10 + .../MotionBlur/Plugins/Runtime.meta | 9 + .../MotionBlur/Plugins/Runtime/VersionInfo.cs | 64 + .../Plugins/Runtime/VersionInfo.cs.meta | 10 + .../MotionBlur/Plugins/SkinnedState.cs | 848 +++++++++ .../MotionBlur/Plugins/SkinnedState.cs.meta | 10 + .../MotionBlur/Plugins/SolidState.cs | 212 +++ .../MotionBlur/Plugins/SolidState.cs.meta | 10 + .../MotionBlur/Plugins/WorkerThreadPool.cs | 182 ++ .../Plugins/WorkerThreadPool.cs.meta | 10 + .../MotionBlur/Resources.meta | 9 + .../MotionBlur/Resources/ClothVectors.shader | 126 ++ .../Resources/ClothVectors.shader.meta | 7 + .../MotionBlur/Resources/Combine.shader | 75 + .../MotionBlur/Resources/Combine.shader.meta | 7 + .../MotionBlur/Resources/Debug.shader | 56 + .../MotionBlur/Resources/Debug.shader.meta | 7 + .../MotionBlur/Resources/Depth.shader | 139 ++ .../MotionBlur/Resources/Depth.shader.meta | 7 + .../MotionBlur/Resources/Dilation.shader | 160 ++ .../MotionBlur/Resources/Dilation.shader.meta | 7 + .../MotionBlur/Resources/GPUSkinDeform.shader | 113 ++ .../Resources/GPUSkinDeform.shader.meta | 7 + .../MotionBlur/Resources/MotionBlurSM2.shader | 35 + .../Resources/MotionBlurSM2.shader.meta | 7 + .../MotionBlur/Resources/MotionBlurSM3.shader | 53 + .../Resources/MotionBlurSM3.shader.meta | 7 + .../Resources/MotionBlurShared.cginc | 236 +++ .../Resources/MotionBlurShared.cginc.meta | 7 + .../Resources/ReprojectionVectors.shader | 73 + .../Resources/ReprojectionVectors.shader.meta | 7 + .../MotionBlur/Resources/Shared.cginc | 59 + .../MotionBlur/Resources/Shared.cginc.meta | 7 + .../Resources/SkinnedVectors.shader | 189 ++ .../Resources/SkinnedVectors.shader.meta | 7 + .../MotionBlur/Resources/SolidVectors.shader | 127 ++ .../Resources/SolidVectors.shader.meta | 7 + .../ScreenSpaceReflection.meta | 9 + .../ScreenSpaceReflection/Editor.meta | 9 + .../Editor/ScreenSpaceReflectionEditor.cs | 156 ++ .../ScreenSpaceReflectionEditor.cs.meta | 12 + .../ScreenSpaceReflection/Resources.meta | 9 + .../Resources/ScreenSpaceRaytrace.cginc | 265 +++ .../Resources/ScreenSpaceRaytrace.cginc.meta | 9 + .../Resources/ScreenSpaceReflection.shader | 1161 ++++++++++++ .../ScreenSpaceReflection.shader.meta | 9 + .../ScreenSpaceReflection.cs | 716 ++++++++ .../ScreenSpaceReflection.cs.meta | 13 + .../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 | 246 +++ .../TonemappingColorGrading.cginc.meta | 9 + .../Resources/TonemappingColorGrading.shader | 304 ++++ .../TonemappingColorGrading.shader.meta | 9 + .../TonemappingColorGrading.cs | 1078 ++++++++++++ .../TonemappingColorGrading.cs.meta | 16 + Assets/QuickRopes 2/CoreScripts.meta | 5 + Assets/QuickRopes 2/CoreScripts/Editor.meta | 5 + .../Editor/QuickRope2ClothEditor.cs | 23 + .../Editor/QuickRope2ClothEditor.cs.meta | 18 + .../CoreScripts/Editor/QuickRope2Editor.cs | 612 +++++++ .../Editor/QuickRope2Editor.cs.meta | 18 + .../CoreScripts/Editor/QuickRope2Menu.cs | 134 ++ .../CoreScripts/Editor/QuickRope2Menu.cs.meta | 18 + .../Editor/QuickRope2MeshEditor.cs | 24 + .../Editor/QuickRope2MeshEditor.cs.meta | 18 + .../Editor/QuickRope2PrefabEditor.cs | 25 + .../Editor/QuickRope2PrefabEditor.cs.meta | 18 + Assets/QuickRopes 2/CoreScripts/QuickRope2.cs | 1002 +++++++++++ .../CoreScripts/QuickRope2.cs.meta | 18 + .../CoreScripts/QuickRope2Cloth.cs | 77 + .../CoreScripts/QuickRope2Cloth.cs.meta | 18 + .../CoreScripts/QuickRope2Helper.cs | 62 + .../CoreScripts/QuickRope2Helper.cs.meta | 18 + .../CoreScripts/QuickRope2Line.cs | 70 + .../CoreScripts/QuickRope2Line.cs.meta | 18 + .../CoreScripts/QuickRope2Mesh.cs | 92 + .../CoreScripts/QuickRope2Mesh.cs.meta | 18 + .../CoreScripts/QuickRope2Prefab.cs | 73 + .../CoreScripts/QuickRope2Prefab.cs.meta | 18 + .../QuickRopes 2/CoreScripts/Resources.meta | 5 + .../CoreScripts/Resources/Link.prefab | 83 + .../CoreScripts/Resources/Link.prefab.meta | 14 + .../Resources/Link_NoCollide.prefab | 70 + .../Resources/Link_NoCollide.prefab.meta | 14 + .../CoreScripts/Resources/Materials.meta | 5 + .../CoreScripts/Resources/Materials/Rope.mat | 35 + .../Resources/Materials/Rope.mat.meta | 4 + .../Resources/Materials/RopeLineMaterial.mat | 59 + .../Materials/RopeLineMaterial.mat.meta | 4 + .../Resources/Materials/WhiteLink.mat | 36 + .../Resources/Materials/WhiteLink.mat.meta | 4 + .../CoreScripts/RopeTubeRenderer.cs | 515 ++++++ .../CoreScripts/RopeTubeRenderer.cs.meta | 18 + Assets/QuickRopes 2/FBX_Files.meta | 5 + Assets/QuickRopes 2/FBX_Files/Crane.meta | 5 + .../FBX_Files/Crane/CraneBase.fbx | Bin 0 -> 31952 bytes .../FBX_Files/Crane/CraneBase.fbx.meta | 63 + .../QuickRopes 2/FBX_Files/Crane/CraneCab.fbx | Bin 0 -> 56112 bytes .../FBX_Files/Crane/CraneCab.fbx.meta | 68 + .../FBX_Files/Crane/CraneHook.fbx | Bin 0 -> 20912 bytes .../FBX_Files/Crane/CraneHook.fbx.meta | 63 + .../FBX_Files/Crane/CraneSegment.fbx | Bin 0 -> 19856 bytes .../FBX_Files/Crane/CraneSegment.fbx.meta | 63 + .../FBX_Files/Crane/Materials.meta | 5 + .../FBX_Files/Crane/Materials/BlackSteel.mat | 28 + .../Crane/Materials/BlackSteel.mat.meta | 4 + .../FBX_Files/Crane/Materials/Cab.mat | 28 + .../FBX_Files/Crane/Materials/Cab.mat.meta | 4 + .../FBX_Files/Crane/Materials/CabGlass.mat | 28 + .../Crane/Materials/CabGlass.mat.meta | 4 + .../FBX_Files/Crane/Materials/Concrete.mat | 28 + .../Crane/Materials/Concrete.mat.meta | 4 + .../FBX_Files/Crane/Materials/Hook.mat | 28 + .../FBX_Files/Crane/Materials/Hook.mat.meta | 4 + .../FBX_Files/Crane/Materials/RedHook5556.mat | 28 + .../Crane/Materials/RedHook5556.mat.meta | 4 + .../FBX_Files/Crane/Materials/YellowSteel.mat | 28 + .../Crane/Materials/YellowSteel.mat.meta | 4 + Assets/QuickRopes 2/FBX_Files/Gear.fbx | Bin 0 -> 42032 bytes Assets/QuickRopes 2/FBX_Files/Gear.fbx.meta | 63 + Assets/QuickRopes 2/FBX_Files/Lamp.fbx | Bin 0 -> 39104 bytes Assets/QuickRopes 2/FBX_Files/Lamp.fbx.meta | 63 + Assets/QuickRopes 2/FBX_Files/Link_FBX.fbx | Bin 0 -> 24880 bytes .../QuickRopes 2/FBX_Files/Link_FBX.fbx.meta | 66 + Assets/QuickRopes 2/FBX_Files/Materials.meta | 5 + .../FBX_Files/Materials/BlackMetal1.mat | 28 + .../FBX_Files/Materials/BlackMetal1.mat.meta | 4 + .../FBX_Files/Materials/LitPaper.mat | 28 + .../FBX_Files/Materials/LitPaper.mat.meta | 4 + .../FBX_Files/Materials/Rust_Scale.mat | 28 + .../FBX_Files/Materials/Rust_Scale.mat.meta | 4 + .../QuickRopes 2/FBX_Files/Materials/Wood.mat | 28 + .../FBX_Files/Materials/Wood.mat.meta | 4 + .../FBX_Files/Materials/lambert1.mat | 28 + .../FBX_Files/Materials/lambert1.mat.meta | 4 + .../FBX_Files/PlanetaryGearSet.fbx | Bin 0 -> 87808 bytes .../FBX_Files/PlanetaryGearSet.fbx.meta | 83 + Assets/QuickRopes 2/FBX_Files/RustyHook.fbx | Bin 0 -> 42800 bytes .../QuickRopes 2/FBX_Files/RustyHook.fbx.meta | 63 + Assets/Scripts/Fie/Camera/FieCameraBase.cs | 84 +- .../Fie/Title/FieTitleAuthController.cs | 28 +- fie.csproj | 54 + 322 files changed, 27962 insertions(+), 56 deletions(-) create mode 100644 Assets/Cinematic Effects/AmbientOcclusion.meta create mode 100644 Assets/Cinematic Effects/AmbientOcclusion/AmbientOcclusion.cs create mode 100644 Assets/Cinematic Effects/AmbientOcclusion/AmbientOcclusion.cs.meta create mode 100644 Assets/Cinematic Effects/AmbientOcclusion/Editor.meta create mode 100644 Assets/Cinematic Effects/AmbientOcclusion/Editor/AmbientOcclusionEditor.cs create mode 100644 Assets/Cinematic Effects/AmbientOcclusion/Editor/AmbientOcclusionEditor.cs.meta create mode 100644 Assets/Cinematic Effects/AmbientOcclusion/Helpers.meta create mode 100644 Assets/Cinematic Effects/AmbientOcclusion/Helpers/PropertyObserver.cs create mode 100644 Assets/Cinematic Effects/AmbientOcclusion/Helpers/PropertyObserver.cs.meta create mode 100644 Assets/Cinematic Effects/AmbientOcclusion/Helpers/Settings.cs create mode 100644 Assets/Cinematic Effects/AmbientOcclusion/Helpers/Settings.cs.meta create mode 100644 Assets/Cinematic Effects/AmbientOcclusion/Resources.meta create mode 100644 Assets/Cinematic Effects/AmbientOcclusion/Resources/AmbientOcclusion.shader create mode 100644 Assets/Cinematic Effects/AmbientOcclusion/Resources/AmbientOcclusion.shader.meta create mode 100644 Assets/Cinematic Effects/Bloom.meta create mode 100644 Assets/Cinematic Effects/Bloom/Bloom.cs create mode 100644 Assets/Cinematic Effects/Bloom/Bloom.cs.meta create mode 100644 Assets/Cinematic Effects/Bloom/Editor.meta create mode 100644 Assets/Cinematic Effects/Bloom/Editor/BloomEditor.cs create mode 100644 Assets/Cinematic Effects/Bloom/Editor/BloomEditor.cs.meta create mode 100644 Assets/Cinematic Effects/Bloom/Resources.meta create mode 100644 Assets/Cinematic Effects/Bloom/Resources/Bloom.shader create mode 100644 Assets/Cinematic Effects/Bloom/Resources/Bloom.shader.meta create mode 100644 Assets/Cinematic Effects/BloomBeta.meta create mode 100644 Assets/Cinematic Effects/BloomBeta/Editor.meta create mode 100644 Assets/Cinematic Effects/BloomBeta/Editor/BokehTextureGenerator.cs create mode 100644 Assets/Cinematic Effects/BloomBeta/Editor/BokehTextureGenerator.cs.meta create mode 100644 Assets/Cinematic Effects/BloomBeta/Editor/UltimateBloomEditor.cs create mode 100644 Assets/Cinematic Effects/BloomBeta/Editor/UltimateBloomEditor.cs.meta create mode 100644 Assets/Cinematic Effects/BloomBeta/Graphics.meta create mode 100644 Assets/Cinematic Effects/BloomBeta/Graphics/Bokeh.png create mode 100644 Assets/Cinematic Effects/BloomBeta/Graphics/Bokeh.png.meta create mode 100644 Assets/Cinematic Effects/BloomBeta/Graphics/BokehRound.png create mode 100644 Assets/Cinematic Effects/BloomBeta/Graphics/BokehRound.png.meta create mode 100644 Assets/Cinematic Effects/BloomBeta/Graphics/Bokehround2.png create mode 100644 Assets/Cinematic Effects/BloomBeta/Graphics/Bokehround2.png.meta create mode 100644 Assets/Cinematic Effects/BloomBeta/Graphics/FlareMask.png create mode 100644 Assets/Cinematic Effects/BloomBeta/Graphics/FlareMask.png.meta create mode 100644 Assets/Cinematic Effects/BloomBeta/Graphics/FlareMaterial.mat create mode 100644 Assets/Cinematic Effects/BloomBeta/Graphics/FlareMaterial.mat.meta create mode 100644 Assets/Cinematic Effects/BloomBeta/ImgForDirtGenerator.meta create mode 100644 Assets/Cinematic Effects/BloomBeta/ImgForDirtGenerator/BokehAlpha.png create mode 100644 Assets/Cinematic Effects/BloomBeta/ImgForDirtGenerator/BokehAlpha.png.meta create mode 100644 Assets/Cinematic Effects/BloomBeta/ImgForDirtGenerator/BokehRoundAlpha1.png create mode 100644 Assets/Cinematic Effects/BloomBeta/ImgForDirtGenerator/BokehRoundAlpha1.png.meta create mode 100644 Assets/Cinematic Effects/BloomBeta/ImgForDirtGenerator/BokehRoundAlpha2.png create mode 100644 Assets/Cinematic Effects/BloomBeta/ImgForDirtGenerator/BokehRoundAlpha2.png.meta create mode 100644 Assets/Cinematic Effects/BloomBeta/Resources.meta create mode 100644 Assets/Cinematic Effects/BloomBeta/Resources/ShadersSimplified.zip create mode 100644 Assets/Cinematic Effects/BloomBeta/Resources/ShadersSimplified.zip.meta create mode 100644 Assets/Cinematic Effects/BloomBeta/Resources/UltimateBloomBokehMisc.shader create mode 100644 Assets/Cinematic Effects/BloomBeta/Resources/UltimateBloomBokehMisc.shader.meta create mode 100644 Assets/Cinematic Effects/BloomBeta/Resources/UltimateBloomCombine.shader create mode 100644 Assets/Cinematic Effects/BloomBeta/Resources/UltimateBloomCombine.shader.meta create mode 100644 Assets/Cinematic Effects/BloomBeta/Resources/UltimateBloomCombineCore.cginc create mode 100644 Assets/Cinematic Effects/BloomBeta/Resources/UltimateBloomCombineCore.cginc.meta create mode 100644 Assets/Cinematic Effects/BloomBeta/Resources/UltimateBloomCombineFlareDirt.shader create mode 100644 Assets/Cinematic Effects/BloomBeta/Resources/UltimateBloomCombineFlareDirt.shader.meta create mode 100644 Assets/Cinematic Effects/BloomBeta/Resources/UltimateBloomMixer.shader create mode 100644 Assets/Cinematic Effects/BloomBeta/Resources/UltimateBloomMixer.shader.meta create mode 100644 Assets/Cinematic Effects/BloomBeta/Resources/UltimateBloomShader.shader create mode 100644 Assets/Cinematic Effects/BloomBeta/Resources/UltimateBloomShader.shader.meta create mode 100644 Assets/Cinematic Effects/BloomBeta/Resources/UltimateBokehTexture.shader create mode 100644 Assets/Cinematic Effects/BloomBeta/Resources/UltimateBokehTexture.shader.meta create mode 100644 Assets/Cinematic Effects/BloomBeta/Resources/UltimateBrightpassCore.cginc create mode 100644 Assets/Cinematic Effects/BloomBeta/Resources/UltimateBrightpassCore.cginc.meta create mode 100644 Assets/Cinematic Effects/BloomBeta/Resources/UltimateBrightpassMask.shader create mode 100644 Assets/Cinematic Effects/BloomBeta/Resources/UltimateBrightpassMask.shader.meta create mode 100644 Assets/Cinematic Effects/BloomBeta/Resources/UltimateFlareCore.cginc create mode 100644 Assets/Cinematic Effects/BloomBeta/Resources/UltimateFlareCore.cginc.meta create mode 100644 Assets/Cinematic Effects/BloomBeta/Resources/UltimateFlareDouble.shader create mode 100644 Assets/Cinematic Effects/BloomBeta/Resources/UltimateFlareDouble.shader.meta create mode 100644 Assets/Cinematic Effects/BloomBeta/Resources/UltimateFlareMask.shader create mode 100644 Assets/Cinematic Effects/BloomBeta/Resources/UltimateFlareMask.shader.meta create mode 100644 Assets/Cinematic Effects/BloomBeta/Resources/UltimateFlareMeshShader.shader create mode 100644 Assets/Cinematic Effects/BloomBeta/Resources/UltimateFlareMeshShader.shader.meta create mode 100644 Assets/Cinematic Effects/BloomBeta/Resources/UltimateFlareSingle.shader create mode 100644 Assets/Cinematic Effects/BloomBeta/Resources/UltimateFlareSingle.shader.meta create mode 100644 Assets/Cinematic Effects/BloomBeta/Resources/UltimateSampling.shader create mode 100644 Assets/Cinematic Effects/BloomBeta/Resources/UltimateSampling.shader.meta create mode 100644 Assets/Cinematic Effects/BloomBeta/Scripts.meta create mode 100644 Assets/Cinematic Effects/BloomBeta/Scripts/BokehRenderer.cs create mode 100644 Assets/Cinematic Effects/BloomBeta/Scripts/BokehRenderer.cs.meta create mode 100644 Assets/Cinematic Effects/BloomBeta/Scripts/DeluxeFilmicCurve.cs create mode 100644 Assets/Cinematic Effects/BloomBeta/Scripts/DeluxeFilmicCurve.cs.meta create mode 100644 Assets/Cinematic Effects/BloomBeta/Scripts/UBHelper.cs create mode 100644 Assets/Cinematic Effects/BloomBeta/Scripts/UBHelper.cs.meta create mode 100644 Assets/Cinematic Effects/BloomBeta/Scripts/UltimateBloom.cs create mode 100644 Assets/Cinematic Effects/BloomBeta/Scripts/UltimateBloom.cs.meta create mode 100644 Assets/Cinematic Effects/BloomBeta/UltimateBloomPathLocator.cs create mode 100644 Assets/Cinematic Effects/BloomBeta/UltimateBloomPathLocator.cs.meta create mode 100644 Assets/Cinematic Effects/Common.meta create mode 100644 Assets/Cinematic Effects/Common/Editor.meta create mode 100644 Assets/Cinematic Effects/Common/Editor/EditorGUIHelper.cs create mode 100644 Assets/Cinematic Effects/Common/Editor/EditorGUIHelper.cs.meta create mode 100644 Assets/Cinematic Effects/Common/Editor/FieldFinder.cs create mode 100644 Assets/Cinematic Effects/Common/Editor/FieldFinder.cs.meta create mode 100644 Assets/Cinematic Effects/Common/Editor/MinDrawer.cs create mode 100644 Assets/Cinematic Effects/Common/Editor/MinDrawer.cs.meta create mode 100644 Assets/Cinematic Effects/Common/ImageEffectHelper.cs create mode 100644 Assets/Cinematic Effects/Common/ImageEffectHelper.cs.meta create mode 100644 Assets/Cinematic Effects/Common/MinAttribute.cs create mode 100644 Assets/Cinematic Effects/Common/MinAttribute.cs.meta create mode 100644 Assets/Cinematic Effects/Common/RenderTextureUtility.cs create mode 100644 Assets/Cinematic Effects/Common/RenderTextureUtility.cs.meta create mode 100644 Assets/Cinematic Effects/DepthOfField.meta create mode 100644 Assets/Cinematic Effects/DepthOfField/DepthOfField.cs create mode 100644 Assets/Cinematic Effects/DepthOfField/DepthOfField.cs.meta create mode 100644 Assets/Cinematic Effects/DepthOfField/Editor.meta create mode 100644 Assets/Cinematic Effects/DepthOfField/Editor/DepthOfFieldEditor.cs create mode 100644 Assets/Cinematic Effects/DepthOfField/Editor/DepthOfFieldEditor.cs.meta create mode 100644 Assets/Cinematic Effects/DepthOfField/Helpers.meta create mode 100644 Assets/Cinematic Effects/DepthOfField/Helpers/HexShape.psd create mode 100644 Assets/Cinematic Effects/DepthOfField/Helpers/HexShape.psd.meta create mode 100644 Assets/Cinematic Effects/DepthOfField/Helpers/RoundedHexShape.tif create mode 100644 Assets/Cinematic Effects/DepthOfField/Helpers/RoundedHexShape.tif.meta create mode 100644 Assets/Cinematic Effects/DepthOfField/Helpers/SphereShape.psd create mode 100644 Assets/Cinematic Effects/DepthOfField/Helpers/SphereShape.psd.meta create mode 100644 Assets/Cinematic Effects/DepthOfField/Resources.meta create mode 100644 Assets/Cinematic Effects/DepthOfField/Resources/BokehSplatting.shader create mode 100644 Assets/Cinematic Effects/DepthOfField/Resources/BokehSplatting.shader.meta create mode 100644 Assets/Cinematic Effects/DepthOfField/Resources/DepthOfField.shader create mode 100644 Assets/Cinematic Effects/DepthOfField/Resources/DepthOfField.shader.meta create mode 100644 Assets/Cinematic Effects/DepthOfField/Resources/MedianFilter.shader create mode 100644 Assets/Cinematic Effects/DepthOfField/Resources/MedianFilter.shader.meta create mode 100644 Assets/Cinematic Effects/LensAberrations.meta create mode 100644 Assets/Cinematic Effects/LensAberrations/Editor.meta create mode 100644 Assets/Cinematic Effects/LensAberrations/Editor/LensAberrationsEditor.cs create mode 100644 Assets/Cinematic Effects/LensAberrations/Editor/LensAberrationsEditor.cs.meta create mode 100644 Assets/Cinematic Effects/LensAberrations/LensAberrations.cs create mode 100644 Assets/Cinematic Effects/LensAberrations/LensAberrations.cs.meta create mode 100644 Assets/Cinematic Effects/LensAberrations/Resources.meta create mode 100644 Assets/Cinematic Effects/LensAberrations/Resources/LensAberrations.shader create mode 100644 Assets/Cinematic Effects/LensAberrations/Resources/LensAberrations.shader.meta create mode 100644 Assets/Cinematic Effects/MotionBlur.meta create mode 100644 Assets/Cinematic Effects/MotionBlur/Plugins.meta create mode 100644 Assets/Cinematic Effects/MotionBlur/Plugins/AmplifyMotion.dll create mode 100644 Assets/Cinematic Effects/MotionBlur/Plugins/AmplifyMotion.dll.meta create mode 100644 Assets/Cinematic Effects/MotionBlur/Plugins/AmplifyMotionBase.cs create mode 100644 Assets/Cinematic Effects/MotionBlur/Plugins/AmplifyMotionBase.cs.meta create mode 100644 Assets/Cinematic Effects/MotionBlur/Plugins/AmplifyMotionCamera.cs create mode 100644 Assets/Cinematic Effects/MotionBlur/Plugins/AmplifyMotionCamera.cs.meta create mode 100644 Assets/Cinematic Effects/MotionBlur/Plugins/AmplifyMotionEffect.cs create mode 100644 Assets/Cinematic Effects/MotionBlur/Plugins/AmplifyMotionEffect.cs.meta create mode 100644 Assets/Cinematic Effects/MotionBlur/Plugins/AmplifyMotionObject.cs create mode 100644 Assets/Cinematic Effects/MotionBlur/Plugins/AmplifyMotionObject.cs.meta create mode 100644 Assets/Cinematic Effects/MotionBlur/Plugins/AmplifyMotionObjectBase.cs create mode 100644 Assets/Cinematic Effects/MotionBlur/Plugins/AmplifyMotionObjectBase.cs.meta create mode 100644 Assets/Cinematic Effects/MotionBlur/Plugins/AmplifyMotionPostProcess.cs create mode 100644 Assets/Cinematic Effects/MotionBlur/Plugins/AmplifyMotionPostProcess.cs.meta create mode 100644 Assets/Cinematic Effects/MotionBlur/Plugins/ClothState.cs create mode 100644 Assets/Cinematic Effects/MotionBlur/Plugins/ClothState.cs.meta create mode 100644 Assets/Cinematic Effects/MotionBlur/Plugins/Editor.meta create mode 100644 Assets/Cinematic Effects/MotionBlur/Plugins/Editor/About.cs create mode 100644 Assets/Cinematic Effects/MotionBlur/Plugins/Editor/About.cs.meta create mode 100644 Assets/Cinematic Effects/MotionBlur/Plugins/Editor/AmplifyMotionEditor.dll create mode 100644 Assets/Cinematic Effects/MotionBlur/Plugins/Editor/AmplifyMotionEditor.dll.meta create mode 100644 Assets/Cinematic Effects/MotionBlur/Plugins/Editor/AmplifyMotionObjectEditor.cs create mode 100644 Assets/Cinematic Effects/MotionBlur/Plugins/Editor/AmplifyMotionObjectEditor.cs.meta create mode 100644 Assets/Cinematic Effects/MotionBlur/Plugins/Editor/AmplifyMotionObjectEditorBase.cs create mode 100644 Assets/Cinematic Effects/MotionBlur/Plugins/Editor/AmplifyMotionObjectEditorBase.cs.meta create mode 100644 Assets/Cinematic Effects/MotionBlur/Plugins/Editor/Resources.meta create mode 100644 Assets/Cinematic Effects/MotionBlur/Plugins/Editor/Resources/effect-icon.png create mode 100644 Assets/Cinematic Effects/MotionBlur/Plugins/Editor/Resources/effect-icon.png.meta create mode 100644 Assets/Cinematic Effects/MotionBlur/Plugins/Editor/Resources/object-icon.tif create mode 100644 Assets/Cinematic Effects/MotionBlur/Plugins/Editor/Resources/object-icon.tif.meta create mode 100644 Assets/Cinematic Effects/MotionBlur/Plugins/ParticleState.cs create mode 100644 Assets/Cinematic Effects/MotionBlur/Plugins/ParticleState.cs.meta create mode 100644 Assets/Cinematic Effects/MotionBlur/Plugins/Runtime.meta create mode 100644 Assets/Cinematic Effects/MotionBlur/Plugins/Runtime/VersionInfo.cs create mode 100644 Assets/Cinematic Effects/MotionBlur/Plugins/Runtime/VersionInfo.cs.meta create mode 100644 Assets/Cinematic Effects/MotionBlur/Plugins/SkinnedState.cs create mode 100644 Assets/Cinematic Effects/MotionBlur/Plugins/SkinnedState.cs.meta create mode 100644 Assets/Cinematic Effects/MotionBlur/Plugins/SolidState.cs create mode 100644 Assets/Cinematic Effects/MotionBlur/Plugins/SolidState.cs.meta create mode 100644 Assets/Cinematic Effects/MotionBlur/Plugins/WorkerThreadPool.cs create mode 100644 Assets/Cinematic Effects/MotionBlur/Plugins/WorkerThreadPool.cs.meta create mode 100644 Assets/Cinematic Effects/MotionBlur/Resources.meta create mode 100644 Assets/Cinematic Effects/MotionBlur/Resources/ClothVectors.shader create mode 100644 Assets/Cinematic Effects/MotionBlur/Resources/ClothVectors.shader.meta create mode 100644 Assets/Cinematic Effects/MotionBlur/Resources/Combine.shader create mode 100644 Assets/Cinematic Effects/MotionBlur/Resources/Combine.shader.meta create mode 100644 Assets/Cinematic Effects/MotionBlur/Resources/Debug.shader create mode 100644 Assets/Cinematic Effects/MotionBlur/Resources/Debug.shader.meta create mode 100644 Assets/Cinematic Effects/MotionBlur/Resources/Depth.shader create mode 100644 Assets/Cinematic Effects/MotionBlur/Resources/Depth.shader.meta create mode 100644 Assets/Cinematic Effects/MotionBlur/Resources/Dilation.shader create mode 100644 Assets/Cinematic Effects/MotionBlur/Resources/Dilation.shader.meta create mode 100644 Assets/Cinematic Effects/MotionBlur/Resources/GPUSkinDeform.shader create mode 100644 Assets/Cinematic Effects/MotionBlur/Resources/GPUSkinDeform.shader.meta create mode 100644 Assets/Cinematic Effects/MotionBlur/Resources/MotionBlurSM2.shader create mode 100644 Assets/Cinematic Effects/MotionBlur/Resources/MotionBlurSM2.shader.meta create mode 100644 Assets/Cinematic Effects/MotionBlur/Resources/MotionBlurSM3.shader create mode 100644 Assets/Cinematic Effects/MotionBlur/Resources/MotionBlurSM3.shader.meta create mode 100644 Assets/Cinematic Effects/MotionBlur/Resources/MotionBlurShared.cginc create mode 100644 Assets/Cinematic Effects/MotionBlur/Resources/MotionBlurShared.cginc.meta create mode 100644 Assets/Cinematic Effects/MotionBlur/Resources/ReprojectionVectors.shader create mode 100644 Assets/Cinematic Effects/MotionBlur/Resources/ReprojectionVectors.shader.meta create mode 100644 Assets/Cinematic Effects/MotionBlur/Resources/Shared.cginc create mode 100644 Assets/Cinematic Effects/MotionBlur/Resources/Shared.cginc.meta create mode 100644 Assets/Cinematic Effects/MotionBlur/Resources/SkinnedVectors.shader create mode 100644 Assets/Cinematic Effects/MotionBlur/Resources/SkinnedVectors.shader.meta create mode 100644 Assets/Cinematic Effects/MotionBlur/Resources/SolidVectors.shader create mode 100644 Assets/Cinematic Effects/MotionBlur/Resources/SolidVectors.shader.meta create mode 100644 Assets/Cinematic Effects/ScreenSpaceReflection.meta create mode 100644 Assets/Cinematic Effects/ScreenSpaceReflection/Editor.meta create mode 100644 Assets/Cinematic Effects/ScreenSpaceReflection/Editor/ScreenSpaceReflectionEditor.cs create mode 100644 Assets/Cinematic Effects/ScreenSpaceReflection/Editor/ScreenSpaceReflectionEditor.cs.meta create mode 100644 Assets/Cinematic Effects/ScreenSpaceReflection/Resources.meta create mode 100644 Assets/Cinematic Effects/ScreenSpaceReflection/Resources/ScreenSpaceRaytrace.cginc create mode 100644 Assets/Cinematic Effects/ScreenSpaceReflection/Resources/ScreenSpaceRaytrace.cginc.meta create mode 100644 Assets/Cinematic Effects/ScreenSpaceReflection/Resources/ScreenSpaceReflection.shader create mode 100644 Assets/Cinematic Effects/ScreenSpaceReflection/Resources/ScreenSpaceReflection.shader.meta create mode 100644 Assets/Cinematic Effects/ScreenSpaceReflection/ScreenSpaceReflection.cs create mode 100644 Assets/Cinematic Effects/ScreenSpaceReflection/ScreenSpaceReflection.cs.meta create mode 100644 Assets/Cinematic Effects/TonemappingColorGrading.meta create mode 100644 Assets/Cinematic Effects/TonemappingColorGrading/Editor.meta create mode 100644 Assets/Cinematic Effects/TonemappingColorGrading/Editor/TonemappingColorGradingEditor.cs create mode 100644 Assets/Cinematic Effects/TonemappingColorGrading/Editor/TonemappingColorGradingEditor.cs.meta create mode 100644 Assets/Cinematic Effects/TonemappingColorGrading/Helpers.meta create mode 100644 Assets/Cinematic Effects/TonemappingColorGrading/Helpers/NeutralLUT16.png create mode 100644 Assets/Cinematic Effects/TonemappingColorGrading/Helpers/NeutralLUT16.png.meta create mode 100644 Assets/Cinematic Effects/TonemappingColorGrading/Helpers/NeutralLUT32.png create mode 100644 Assets/Cinematic Effects/TonemappingColorGrading/Helpers/NeutralLUT32.png.meta create mode 100644 Assets/Cinematic Effects/TonemappingColorGrading/Resources.meta create mode 100644 Assets/Cinematic Effects/TonemappingColorGrading/Resources/HistogramCompute.compute create mode 100644 Assets/Cinematic Effects/TonemappingColorGrading/Resources/HistogramCompute.compute.meta create mode 100644 Assets/Cinematic Effects/TonemappingColorGrading/Resources/HistogramRender.shader create mode 100644 Assets/Cinematic Effects/TonemappingColorGrading/Resources/HistogramRender.shader.meta create mode 100644 Assets/Cinematic Effects/TonemappingColorGrading/Resources/TonemappingColorGrading.cginc create mode 100644 Assets/Cinematic Effects/TonemappingColorGrading/Resources/TonemappingColorGrading.cginc.meta create mode 100644 Assets/Cinematic Effects/TonemappingColorGrading/Resources/TonemappingColorGrading.shader create mode 100644 Assets/Cinematic Effects/TonemappingColorGrading/Resources/TonemappingColorGrading.shader.meta create mode 100644 Assets/Cinematic Effects/TonemappingColorGrading/TonemappingColorGrading.cs create mode 100644 Assets/Cinematic Effects/TonemappingColorGrading/TonemappingColorGrading.cs.meta create mode 100644 Assets/QuickRopes 2/CoreScripts.meta create mode 100644 Assets/QuickRopes 2/CoreScripts/Editor.meta create mode 100644 Assets/QuickRopes 2/CoreScripts/Editor/QuickRope2ClothEditor.cs create mode 100644 Assets/QuickRopes 2/CoreScripts/Editor/QuickRope2ClothEditor.cs.meta create mode 100644 Assets/QuickRopes 2/CoreScripts/Editor/QuickRope2Editor.cs create mode 100644 Assets/QuickRopes 2/CoreScripts/Editor/QuickRope2Editor.cs.meta create mode 100644 Assets/QuickRopes 2/CoreScripts/Editor/QuickRope2Menu.cs create mode 100644 Assets/QuickRopes 2/CoreScripts/Editor/QuickRope2Menu.cs.meta create mode 100644 Assets/QuickRopes 2/CoreScripts/Editor/QuickRope2MeshEditor.cs create mode 100644 Assets/QuickRopes 2/CoreScripts/Editor/QuickRope2MeshEditor.cs.meta create mode 100644 Assets/QuickRopes 2/CoreScripts/Editor/QuickRope2PrefabEditor.cs create mode 100644 Assets/QuickRopes 2/CoreScripts/Editor/QuickRope2PrefabEditor.cs.meta create mode 100644 Assets/QuickRopes 2/CoreScripts/QuickRope2.cs create mode 100644 Assets/QuickRopes 2/CoreScripts/QuickRope2.cs.meta create mode 100644 Assets/QuickRopes 2/CoreScripts/QuickRope2Cloth.cs create mode 100644 Assets/QuickRopes 2/CoreScripts/QuickRope2Cloth.cs.meta create mode 100644 Assets/QuickRopes 2/CoreScripts/QuickRope2Helper.cs create mode 100644 Assets/QuickRopes 2/CoreScripts/QuickRope2Helper.cs.meta create mode 100644 Assets/QuickRopes 2/CoreScripts/QuickRope2Line.cs create mode 100644 Assets/QuickRopes 2/CoreScripts/QuickRope2Line.cs.meta create mode 100644 Assets/QuickRopes 2/CoreScripts/QuickRope2Mesh.cs create mode 100644 Assets/QuickRopes 2/CoreScripts/QuickRope2Mesh.cs.meta create mode 100644 Assets/QuickRopes 2/CoreScripts/QuickRope2Prefab.cs create mode 100644 Assets/QuickRopes 2/CoreScripts/QuickRope2Prefab.cs.meta create mode 100644 Assets/QuickRopes 2/CoreScripts/Resources.meta create mode 100644 Assets/QuickRopes 2/CoreScripts/Resources/Link.prefab create mode 100644 Assets/QuickRopes 2/CoreScripts/Resources/Link.prefab.meta create mode 100644 Assets/QuickRopes 2/CoreScripts/Resources/Link_NoCollide.prefab create mode 100644 Assets/QuickRopes 2/CoreScripts/Resources/Link_NoCollide.prefab.meta create mode 100644 Assets/QuickRopes 2/CoreScripts/Resources/Materials.meta create mode 100644 Assets/QuickRopes 2/CoreScripts/Resources/Materials/Rope.mat create mode 100644 Assets/QuickRopes 2/CoreScripts/Resources/Materials/Rope.mat.meta create mode 100644 Assets/QuickRopes 2/CoreScripts/Resources/Materials/RopeLineMaterial.mat create mode 100644 Assets/QuickRopes 2/CoreScripts/Resources/Materials/RopeLineMaterial.mat.meta create mode 100644 Assets/QuickRopes 2/CoreScripts/Resources/Materials/WhiteLink.mat create mode 100644 Assets/QuickRopes 2/CoreScripts/Resources/Materials/WhiteLink.mat.meta create mode 100644 Assets/QuickRopes 2/CoreScripts/RopeTubeRenderer.cs create mode 100644 Assets/QuickRopes 2/CoreScripts/RopeTubeRenderer.cs.meta create mode 100644 Assets/QuickRopes 2/FBX_Files.meta create mode 100644 Assets/QuickRopes 2/FBX_Files/Crane.meta create mode 100644 Assets/QuickRopes 2/FBX_Files/Crane/CraneBase.fbx create mode 100644 Assets/QuickRopes 2/FBX_Files/Crane/CraneBase.fbx.meta create mode 100644 Assets/QuickRopes 2/FBX_Files/Crane/CraneCab.fbx create mode 100644 Assets/QuickRopes 2/FBX_Files/Crane/CraneCab.fbx.meta create mode 100644 Assets/QuickRopes 2/FBX_Files/Crane/CraneHook.fbx create mode 100644 Assets/QuickRopes 2/FBX_Files/Crane/CraneHook.fbx.meta create mode 100644 Assets/QuickRopes 2/FBX_Files/Crane/CraneSegment.fbx create mode 100644 Assets/QuickRopes 2/FBX_Files/Crane/CraneSegment.fbx.meta create mode 100644 Assets/QuickRopes 2/FBX_Files/Crane/Materials.meta create mode 100644 Assets/QuickRopes 2/FBX_Files/Crane/Materials/BlackSteel.mat create mode 100644 Assets/QuickRopes 2/FBX_Files/Crane/Materials/BlackSteel.mat.meta create mode 100644 Assets/QuickRopes 2/FBX_Files/Crane/Materials/Cab.mat create mode 100644 Assets/QuickRopes 2/FBX_Files/Crane/Materials/Cab.mat.meta create mode 100644 Assets/QuickRopes 2/FBX_Files/Crane/Materials/CabGlass.mat create mode 100644 Assets/QuickRopes 2/FBX_Files/Crane/Materials/CabGlass.mat.meta create mode 100644 Assets/QuickRopes 2/FBX_Files/Crane/Materials/Concrete.mat create mode 100644 Assets/QuickRopes 2/FBX_Files/Crane/Materials/Concrete.mat.meta create mode 100644 Assets/QuickRopes 2/FBX_Files/Crane/Materials/Hook.mat create mode 100644 Assets/QuickRopes 2/FBX_Files/Crane/Materials/Hook.mat.meta create mode 100644 Assets/QuickRopes 2/FBX_Files/Crane/Materials/RedHook5556.mat create mode 100644 Assets/QuickRopes 2/FBX_Files/Crane/Materials/RedHook5556.mat.meta create mode 100644 Assets/QuickRopes 2/FBX_Files/Crane/Materials/YellowSteel.mat create mode 100644 Assets/QuickRopes 2/FBX_Files/Crane/Materials/YellowSteel.mat.meta create mode 100644 Assets/QuickRopes 2/FBX_Files/Gear.fbx create mode 100644 Assets/QuickRopes 2/FBX_Files/Gear.fbx.meta create mode 100644 Assets/QuickRopes 2/FBX_Files/Lamp.fbx create mode 100644 Assets/QuickRopes 2/FBX_Files/Lamp.fbx.meta create mode 100644 Assets/QuickRopes 2/FBX_Files/Link_FBX.fbx create mode 100644 Assets/QuickRopes 2/FBX_Files/Link_FBX.fbx.meta create mode 100644 Assets/QuickRopes 2/FBX_Files/Materials.meta create mode 100644 Assets/QuickRopes 2/FBX_Files/Materials/BlackMetal1.mat create mode 100644 Assets/QuickRopes 2/FBX_Files/Materials/BlackMetal1.mat.meta create mode 100644 Assets/QuickRopes 2/FBX_Files/Materials/LitPaper.mat create mode 100644 Assets/QuickRopes 2/FBX_Files/Materials/LitPaper.mat.meta create mode 100644 Assets/QuickRopes 2/FBX_Files/Materials/Rust_Scale.mat create mode 100644 Assets/QuickRopes 2/FBX_Files/Materials/Rust_Scale.mat.meta create mode 100644 Assets/QuickRopes 2/FBX_Files/Materials/Wood.mat create mode 100644 Assets/QuickRopes 2/FBX_Files/Materials/Wood.mat.meta create mode 100644 Assets/QuickRopes 2/FBX_Files/Materials/lambert1.mat create mode 100644 Assets/QuickRopes 2/FBX_Files/Materials/lambert1.mat.meta create mode 100644 Assets/QuickRopes 2/FBX_Files/PlanetaryGearSet.fbx create mode 100644 Assets/QuickRopes 2/FBX_Files/PlanetaryGearSet.fbx.meta create mode 100644 Assets/QuickRopes 2/FBX_Files/RustyHook.fbx create mode 100644 Assets/QuickRopes 2/FBX_Files/RustyHook.fbx.meta diff --git a/Assets/Cinematic Effects/AmbientOcclusion.meta b/Assets/Cinematic Effects/AmbientOcclusion.meta new file mode 100644 index 0000000..d6631d6 --- /dev/null +++ b/Assets/Cinematic Effects/AmbientOcclusion.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: ed6d7947a564a4dd1987f60392be4349 +folderAsset: yes +timeCreated: 1457326591 +licenseType: Pro +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/AmbientOcclusion/AmbientOcclusion.cs b/Assets/Cinematic Effects/AmbientOcclusion/AmbientOcclusion.cs new file mode 100644 index 0000000..c3808f9 --- /dev/null +++ b/Assets/Cinematic Effects/AmbientOcclusion/AmbientOcclusion.cs @@ -0,0 +1,347 @@ +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 && isGBufferAvailable; } + } + + #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); + } + } + + bool downsampling + { + get { return settings.downsampling; } + } + + bool ambientOnly + { + get { return settings.ambientOnly && isAmbientOnlySupported; } + } + + // 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; } + + // Check if the G-buffer is available + bool isGBufferAvailable + { + get + { + var path = targetCamera.actualRenderingPath; + return path == RenderingPath.DeferredShading; + } + } + + // 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 = RenderTextureFormat.R8; + 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, 0); + + // 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, 1); + cb.ReleaseTemporaryRT(rtMask); + + cb.GetTemporaryRT(rtMask, tw, th, 0, filter, format, rwMode); + cb.SetGlobalVector("_BlurVector", Vector2.up * 2 * ts); + cb.Blit(rtBlur, rtMask, m, 1); + 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, 2); + cb.ReleaseTemporaryRT(rtMask); + + cb.GetTemporaryRT(rtMask, tw, th, 0, filter, format, rwMode); + cb.SetGlobalVector("_BlurVector", Vector2.up * ts); + cb.Blit(rtBlur, rtMask, m, 2); + 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, 4); + + 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 = RenderTextureFormat.R8; + var rwMode = RenderTextureReadWrite.Linear; + + // AO buffer + var m = aoMaterial; + var rtMask = RenderTexture.GetTemporary(tw / ts, th / ts, 0, format, rwMode); + + // AO estimation + Graphics.Blit((Texture)null, rtMask, m, 0); + + // 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, 1); + RenderTexture.ReleaseTemporary(rtMask); + + rtMask = RenderTexture.GetTemporary(tw, th, 0, format, rwMode); + m.SetVector("_BlurVector", Vector2.up * 2 * ts); + Graphics.Blit(rtBlur, rtMask, m, 1); + 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, 2); + RenderTexture.ReleaseTemporary(rtMask); + + rtMask = RenderTexture.GetTemporary(tw, th, 0, format, rwMode); + m.SetVector("_BlurVector", Vector2.up * ts); + Graphics.Blit(rtBlur, rtMask, m, 2); + RenderTexture.ReleaseTemporary(rtBlur); + + // Combine AO with the source. + m.SetTexture("_OcclusionTexture", rtMask); + + if (!settings.debug) + Graphics.Blit(source, destination, m, 3); + else + Graphics.Blit(source, destination, m, 5); + + RenderTexture.ReleaseTemporary(rtMask); + } + + // Update the common material properties. + void UpdateMaterialProperties() + { + var m = aoMaterial; + m.shaderKeywords = null; + + m.SetFloat("_Intensity", intensity); + m.SetFloat("_Radius", radius); + m.SetFloat("_TargetScale", downsampling ? 0.5f : 1); + + // Use G-buffer if available. + if (isGBufferAvailable) + m.EnableKeyword("_SOURCE_GBUFFER"); + + // Sample count + if (sampleCount == SampleCount.Lowest) + m.EnableKeyword("_SAMPLECOUNT_LOWEST"); + else + 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); + + // Requires DepthNormals when G-buffer is not available. + if (!isGBufferAvailable) + 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/Assets/Cinematic Effects/AmbientOcclusion/AmbientOcclusion.cs.meta b/Assets/Cinematic Effects/AmbientOcclusion/AmbientOcclusion.cs.meta new file mode 100644 index 0000000..30be0c0 --- /dev/null +++ b/Assets/Cinematic Effects/AmbientOcclusion/AmbientOcclusion.cs.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: e89654dcf6db746d2a57aeaaa14f5e83 +timeCreated: 1457327177 +licenseType: Pro +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/Assets/Cinematic Effects/AmbientOcclusion/Editor.meta b/Assets/Cinematic Effects/AmbientOcclusion/Editor.meta new file mode 100644 index 0000000..aedb738 --- /dev/null +++ b/Assets/Cinematic Effects/AmbientOcclusion/Editor.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: c1589efc0706e448d9a0af709e2c99cc +folderAsset: yes +timeCreated: 1457326964 +licenseType: Pro +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/AmbientOcclusion/Editor/AmbientOcclusionEditor.cs b/Assets/Cinematic Effects/AmbientOcclusion/Editor/AmbientOcclusionEditor.cs new file mode 100644 index 0000000..82cae01 --- /dev/null +++ b/Assets/Cinematic Effects/AmbientOcclusion/Editor/AmbientOcclusionEditor.cs @@ -0,0 +1,63 @@ +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 _ambientOnly; + SerializedProperty _debug; + + static GUIContent _textValue = new GUIContent("Value"); + + static string _textNoAmbientOnly = + "The ambient-only mode is currently disabled; " + + "it needs deferred shading and HDR rendering."; + + 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"); + _ambientOnly = serializedObject.FindProperty("settings.ambientOnly"); + _debug = serializedObject.FindProperty("settings.debug"); + } + + public override void OnInspectorGUI() + { + 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(_ambientOnly); + EditorGUILayout.PropertyField(_debug); + + // Show a warning if the ambient-only mode is not supported. + if (!_ambientOnly.hasMultipleDifferentValues && _ambientOnly.boolValue) + if (!((AmbientOcclusion)target).isAmbientOnlySupported) + EditorGUILayout.HelpBox(_textNoAmbientOnly, MessageType.Info); + + serializedObject.ApplyModifiedProperties(); + } + } +} diff --git a/Assets/Cinematic Effects/AmbientOcclusion/Editor/AmbientOcclusionEditor.cs.meta b/Assets/Cinematic Effects/AmbientOcclusion/Editor/AmbientOcclusionEditor.cs.meta new file mode 100644 index 0000000..bb319ee --- /dev/null +++ b/Assets/Cinematic Effects/AmbientOcclusion/Editor/AmbientOcclusionEditor.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 05ea8e27ed8e74e67a9220b4f4119e51 +timeCreated: 1457327141 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/AmbientOcclusion/Helpers.meta b/Assets/Cinematic Effects/AmbientOcclusion/Helpers.meta new file mode 100644 index 0000000..127ad26 --- /dev/null +++ b/Assets/Cinematic Effects/AmbientOcclusion/Helpers.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 1d775599023574a39befabe47bdfddde +folderAsset: yes +timeCreated: 1457326936 +licenseType: Pro +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/AmbientOcclusion/Helpers/PropertyObserver.cs b/Assets/Cinematic Effects/AmbientOcclusion/Helpers/PropertyObserver.cs new file mode 100644 index 0000000..e53f0a4 --- /dev/null +++ b/Assets/Cinematic Effects/AmbientOcclusion/Helpers/PropertyObserver.cs @@ -0,0 +1,38 @@ +using UnityEngine; + +namespace UnityStandardAssets.CinematicEffects +{ + public partial class AmbientOcclusion : MonoBehaviour + { + // Observer class that detects changes on properties + struct PropertyObserver + { + // AO properties + bool _downsampling; + bool _ambientOnly; + + // 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 || + _ambientOnly != setting.ambientOnly || + _pixelWidth != camera.pixelWidth || + _pixelHeight != camera.pixelHeight; + } + + // Update the internal state. + public void Update(Settings setting, Camera camera) + { + _downsampling = setting.downsampling; + _ambientOnly = setting.ambientOnly; + _pixelWidth = camera.pixelWidth; + _pixelHeight = camera.pixelHeight; + } + } + } +} diff --git a/Assets/Cinematic Effects/AmbientOcclusion/Helpers/PropertyObserver.cs.meta b/Assets/Cinematic Effects/AmbientOcclusion/Helpers/PropertyObserver.cs.meta new file mode 100644 index 0000000..2068429 --- /dev/null +++ b/Assets/Cinematic Effects/AmbientOcclusion/Helpers/PropertyObserver.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 1d9548d9a173a40e4b758ecf6e4fed49 +timeCreated: 1457326885 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/AmbientOcclusion/Helpers/Settings.cs b/Assets/Cinematic Effects/AmbientOcclusion/Helpers/Settings.cs new file mode 100644 index 0000000..5ce57f5 --- /dev/null +++ b/Assets/Cinematic Effects/AmbientOcclusion/Helpers/Settings.cs @@ -0,0 +1,71 @@ +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 + } + + /// 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 deferred + /// shading and HDR rendering. + [SerializeField] + [Tooltip("If checked, the effect only affects ambient lighting.")] + public bool ambientOnly; + + [SerializeField] + 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 + }; + } + } + } + } +} diff --git a/Assets/Cinematic Effects/AmbientOcclusion/Helpers/Settings.cs.meta b/Assets/Cinematic Effects/AmbientOcclusion/Helpers/Settings.cs.meta new file mode 100644 index 0000000..0a3a30a --- /dev/null +++ b/Assets/Cinematic Effects/AmbientOcclusion/Helpers/Settings.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: e952a344c72354904a417d27abe6f55e +timeCreated: 1457331804 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/AmbientOcclusion/Resources.meta b/Assets/Cinematic Effects/AmbientOcclusion/Resources.meta new file mode 100644 index 0000000..1719486 --- /dev/null +++ b/Assets/Cinematic Effects/AmbientOcclusion/Resources.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: ae08100d29090452888e1b6a7b5a7170 +folderAsset: yes +timeCreated: 1457326958 +licenseType: Pro +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/AmbientOcclusion/Resources/AmbientOcclusion.shader b/Assets/Cinematic Effects/AmbientOcclusion/Resources/AmbientOcclusion.shader new file mode 100644 index 0000000..f95f84c --- /dev/null +++ b/Assets/Cinematic Effects/AmbientOcclusion/Resources/AmbientOcclusion.shader @@ -0,0 +1,476 @@ +Shader "Hidden/Image Effects/Cinematic/AmbientOcclusion" +{ + Properties + { + _MainTex("", 2D) = ""{} + _OcclusionTexture("", 2D) = ""{} + } + CGINCLUDE + + // -------- + // 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" + + #if _SAMPLECOUNT_LOWEST + static const int _SampleCount = 3; + #else + int _SampleCount; + #endif + + // Global shader properties + #if _SOURCE_GBUFFER + sampler2D _CameraGBufferTexture2; + sampler2D_float _CameraDepthTexture; + float4x4 _WorldToCamera; + #else + sampler2D_float _CameraDepthNormalsTexture; + #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 + 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 * 2 - 1; + return mul((float3x3)_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 + 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 + float3 v_s1 = PickSamplePoint(uv, s); + 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); + } + + // Pass 0: Occlusion estimation + half4 frag_ao(v2f_img i) : SV_Target + { + return EstimateOcclusion(i.uv); + } + + // Pass 1: Primary blur filter + half4 frag_blur1(v2f_img i) : SV_Target + { + float2 delta = _MainTex_TexelSize.xy * _BlurVector; + return SeparableBlurLarge(_MainTex, i.uv, delta); + } + + // Pass 2: Secondary blur filter + half4 frag_blur2(v2f_img i) : SV_Target + { + float2 delta = _MainTex_TexelSize.xy * _BlurVector; + return SeparableBlurSmall(_MainTex, i.uv, delta); + } + + // Pass 3: Combiner 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); + } + + // Pass 4: Combiner 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 + + // Pass 5: 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); + } + + ENDCG + + SubShader + { + Pass + { + ZTest Always Cull Off ZWrite Off + CGPROGRAM + #pragma multi_compile _SOURCE_DEPTHNORMALS _SOURCE_GBUFFER + #pragma multi_compile _ _SAMPLECOUNT_LOWEST + #pragma vertex vert_img + #pragma fragment frag_ao + #pragma target 3.0 + ENDCG + } + Pass + { + ZTest Always Cull Off ZWrite Off + CGPROGRAM + #pragma multi_compile _SOURCE_DEPTHNORMALS _SOURCE_GBUFFER + #pragma vertex vert_img + #pragma fragment frag_blur1 + #pragma target 3.0 + ENDCG + } + Pass + { + ZTest Always Cull Off ZWrite Off + CGPROGRAM + #pragma multi_compile _SOURCE_DEPTHNORMALS _SOURCE_GBUFFER + #pragma vertex vert_img + #pragma fragment frag_blur2 + #pragma target 3.0 + ENDCG + } + Pass + { + ZTest Always Cull Off ZWrite Off + CGPROGRAM + #pragma vertex vert_multitex + #pragma fragment frag_combine + #pragma target 3.0 + ENDCG + } + Pass + { + Blend Zero OneMinusSrcColor, Zero OneMinusSrcAlpha + ZTest Always Cull Off ZWrite Off + CGPROGRAM + #pragma vertex vert_gbuffer + #pragma fragment frag_gbuffer_combine + #pragma target 3.0 + ENDCG + } + Pass + { + ZTest Always Cull Off ZWrite Off + CGPROGRAM + #pragma vertex vert_multitex + #pragma fragment frag_blit_ao + #pragma target 3.0 + ENDCG + } + } +} diff --git a/Assets/Cinematic Effects/AmbientOcclusion/Resources/AmbientOcclusion.shader.meta b/Assets/Cinematic Effects/AmbientOcclusion/Resources/AmbientOcclusion.shader.meta new file mode 100644 index 0000000..b7de14f --- /dev/null +++ b/Assets/Cinematic Effects/AmbientOcclusion/Resources/AmbientOcclusion.shader.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 65e203e5acda447acbf9dc1ef78c4a39 +timeCreated: 1457327141 +licenseType: Pro +ShaderImporter: + defaultTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/Bloom.meta b/Assets/Cinematic Effects/Bloom.meta new file mode 100644 index 0000000..7cd206d --- /dev/null +++ b/Assets/Cinematic Effects/Bloom.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 193f90bb87f484c62ad73788d9cb2d44 +folderAsset: yes +timeCreated: 1454052266 +licenseType: Pro +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/Bloom/Bloom.cs b/Assets/Cinematic Effects/Bloom/Bloom.cs new file mode 100644 index 0000000..fadd47f --- /dev/null +++ b/Assets/Cinematic Effects/Bloom/Bloom.cs @@ -0,0 +1,223 @@ +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(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, + 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; + var isGamma = QualitySettings.activeColorSpace == ColorSpace.Gamma; + + // 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); + + const float softKneeRatio = 0.5f; + var knee = threshold * softKneeRatio + 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)); + + if (settings.highQuality) + material.EnableKeyword("HIGH_QUALITY"); + else + material.DisableKeyword("HIGH_QUALITY"); + + if (settings.antiFlicker) + material.EnableKeyword("ANTI_FLICKER"); + else + material.DisableKeyword("ANTI_FLICKER"); + + if (isGamma) + { + material.DisableKeyword("LINEAR_COLOR"); + material.EnableKeyword("GAMMA_COLOR"); + } + else + { + material.EnableKeyword("LINEAR_COLOR"); + material.DisableKeyword("GAMMA_COLOR"); + } + + // prefilter pass + var prefiltered = RenderTexture.GetTemporary(tw, th, 0, rtFormat); + Graphics.Blit(source, prefiltered, material, 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) ? 1 : 2); + 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, 3); + last = m_blurBuffer2[level]; + } + + // finish process + material.SetTexture("_BaseTex", source); + Graphics.Blit(last, destination, material, 4); + + // 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/Assets/Cinematic Effects/Bloom/Bloom.cs.meta b/Assets/Cinematic Effects/Bloom/Bloom.cs.meta new file mode 100644 index 0000000..95024ea --- /dev/null +++ b/Assets/Cinematic Effects/Bloom/Bloom.cs.meta @@ -0,0 +1,13 @@ +fileFormatVersion: 2 +guid: 32187365ced0c42219cde2b57c99b323 +timeCreated: 1454052338 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: + - _shader: {fileID: 4800000, guid: e45d4f28262b04d10a075856ab5fdb5e, type: 3} + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/Bloom/Editor.meta b/Assets/Cinematic Effects/Bloom/Editor.meta new file mode 100644 index 0000000..0a74df6 --- /dev/null +++ b/Assets/Cinematic Effects/Bloom/Editor.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 92a024b1f1430409eb656f65969aa3d5 +folderAsset: yes +timeCreated: 1454052266 +licenseType: Pro +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/Bloom/Editor/BloomEditor.cs b/Assets/Cinematic Effects/Bloom/Editor/BloomEditor.cs new file mode 100644 index 0000000..0a9e4f1 --- /dev/null +++ b/Assets/Cinematic Effects/Bloom/Editor/BloomEditor.cs @@ -0,0 +1,32 @@ +using System; +using System.Collections.Generic; +using UnityEditor; + +namespace UnityStandardAssets.CinematicEffects +{ + [CanEditMultipleObjects] + [CustomEditor(typeof(Bloom))] + public class BloomEditor : 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(); + foreach (var property in m_Properties) + EditorGUILayout.PropertyField(property); + serializedObject.ApplyModifiedProperties(); + } + } +} diff --git a/Assets/Cinematic Effects/Bloom/Editor/BloomEditor.cs.meta b/Assets/Cinematic Effects/Bloom/Editor/BloomEditor.cs.meta new file mode 100644 index 0000000..3569f9f --- /dev/null +++ b/Assets/Cinematic Effects/Bloom/Editor/BloomEditor.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 38020a6029a85434a95a6f725a5aae5f +timeCreated: 1454052266 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/Bloom/Resources.meta b/Assets/Cinematic Effects/Bloom/Resources.meta new file mode 100644 index 0000000..7099ea8 --- /dev/null +++ b/Assets/Cinematic Effects/Bloom/Resources.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 4af3202dbe79e460e9be42bcb6509fe0 +folderAsset: yes +timeCreated: 1454052266 +licenseType: Pro +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/Bloom/Resources/Bloom.shader b/Assets/Cinematic Effects/Bloom/Resources/Bloom.shader new file mode 100644 index 0000000..9d23541 --- /dev/null +++ b/Assets/Cinematic Effects/Bloom/Resources/Bloom.shader @@ -0,0 +1,284 @@ +Shader "Hidden/Image Effects/Cinematic/Bloom" +{ + Properties + { + _MainTex("", 2D) = "" {} + _BaseTex("", 2D) = "" {} + } + + CGINCLUDE + + #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; + + 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 + 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.0 / (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 + // + + struct v2f_multitex + { + float4 pos : SV_POSITION; + float2 uvMain : TEXCOORD0; + float2 uvBase : TEXCOORD1; + }; + + v2f_multitex vert_multitex(appdata_full v) + { + v2f_multitex o; + o.pos = mul(UNITY_MATRIX_MVP, v.vertex); + o.uvMain = v.texcoord.xy; + o.uvBase = v.texcoord.xy; + #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 GAMMA_COLOR + 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) / (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 GAMMA_COLOR + base.rgb = GammaToLinearSpace(base.rgb); + #endif + half3 cout = base.rgb + blur * _Intensity; + #if GAMMA_COLOR + cout = LinearToGammaSpace(cout); + #endif + return half4(cout, base.a); + } + + ENDCG + SubShader + { + Pass + { + ZTest Always Cull Off ZWrite Off + CGPROGRAM + #pragma multi_compile _ ANTI_FLICKER + #pragma multi_compile LINEAR_COLOR GAMMA_COLOR + #pragma vertex vert_img + #pragma fragment frag_prefilter + #pragma target 3.0 + ENDCG + } + Pass + { + ZTest Always Cull Off ZWrite Off + CGPROGRAM + #pragma multi_compile _ ANTI_FLICKER + #pragma vertex vert_img + #pragma fragment frag_downsample1 + #pragma target 3.0 + ENDCG + } + Pass + { + ZTest Always Cull Off ZWrite Off + CGPROGRAM + #pragma vertex vert_img + #pragma fragment frag_downsample2 + #pragma target 3.0 + ENDCG + } + Pass + { + ZTest Always Cull Off ZWrite Off + CGPROGRAM + #pragma multi_compile _ HIGH_QUALITY + #pragma vertex vert_multitex + #pragma fragment frag_upsample + #pragma target 3.0 + ENDCG + } + Pass + { + ZTest Always Cull Off ZWrite Off + CGPROGRAM + #pragma multi_compile _ HIGH_QUALITY + #pragma multi_compile LINEAR_COLOR GAMMA_COLOR + #pragma vertex vert_multitex + #pragma fragment frag_upsample_final + #pragma target 3.0 + ENDCG + } + } +} diff --git a/Assets/Cinematic Effects/Bloom/Resources/Bloom.shader.meta b/Assets/Cinematic Effects/Bloom/Resources/Bloom.shader.meta new file mode 100644 index 0000000..c2a82ba --- /dev/null +++ b/Assets/Cinematic Effects/Bloom/Resources/Bloom.shader.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: e45d4f28262b04d10a075856ab5fdb5e +timeCreated: 1454052270 +licenseType: Pro +ShaderImporter: + defaultTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/BloomBeta.meta b/Assets/Cinematic Effects/BloomBeta.meta new file mode 100644 index 0000000..4421927 --- /dev/null +++ b/Assets/Cinematic Effects/BloomBeta.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: c6eb038cfff9e4dd990eeca4d9f4013f +folderAsset: yes +timeCreated: 1461974392 +licenseType: Pro +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/BloomBeta/Editor.meta b/Assets/Cinematic Effects/BloomBeta/Editor.meta new file mode 100644 index 0000000..ea5e5ab --- /dev/null +++ b/Assets/Cinematic Effects/BloomBeta/Editor.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 59c160308a8e47545a7b1baa9377c744 +folderAsset: yes +timeCreated: 1443580217 +licenseType: Store +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/BloomBeta/Editor/BokehTextureGenerator.cs b/Assets/Cinematic Effects/BloomBeta/Editor/BokehTextureGenerator.cs new file mode 100644 index 0000000..2510b00 --- /dev/null +++ b/Assets/Cinematic Effects/BloomBeta/Editor/BokehTextureGenerator.cs @@ -0,0 +1,526 @@ +using UnityEngine; +using System.Collections.Generic; +using UnityEditor; +using System.IO; +using System; + +public class CameraDirtTextureGenerator : EditorWindow +{ + + + Texture2D m_DestinationTexture = null; + + [SerializeField] + int m_PassCount; + + + [SerializeField] + BokehGenerationPass[] m_BokehPasses = new BokehGenerationPass[5]; + + [Serializable] + class BokehGenerationPass + { + [SerializeField] + public Texture2D m_BokehTexture; + [SerializeField] + public float m_MinimumSize = 100.0f; + [SerializeField] + public float m_MaximumSize = 200.0f; + [SerializeField] + public float m_Density = 0.1f; + [SerializeField] + public float m_MinIntensity = 0.1f; + [SerializeField] + public float m_MaxIntensity = 0.3f; + [SerializeField] + public float m_BlurRadius = 1; + [SerializeField] + public float m_VignettePower = 0.5f; + [SerializeField] + public float m_ChromaticAberration = 20.0f; + [SerializeField] + public float m_HueVariation = 0.3f; + [SerializeField] + public bool m_RandomRotation = false; + } + + List[] m_Positions = new List[5]; + float[] m_MinimumDistance = new float[5]; + + Vector2 m_ScrollPos; + + [MenuItem("Window/Bokeh Texture Generator")] + public static void ShowWindow() + { + EditorWindow.GetWindow(typeof(CameraDirtTextureGenerator)); + } + + + GUIStyle m_Background1; + GUIStyle m_Background2; + GUIStyle m_Background3; + GUIStyle m_Background4; + void OnEnable() + { + m_Background1 = new GUIStyle(); + m_Background1.normal.background = MakeTex(600, 1, new Color(1.0f, 1.0f, 1.0f, 0.1f)); + m_Background2 = new GUIStyle(); + m_Background2.normal.background = MakeTex(600, 1, new Color(1.0f, 1.0f, 1.0f, 0.0f)); + m_Background3 = new GUIStyle(); + m_Background3.normal.background = MakeTex(600, 1, new Color(1.0f, 1.0f, 1.0f, 0.05f)); + m_Background4 = new GUIStyle(); + m_Background4.normal.background = MakeTex(600, 1, new Color(0.0f, 0.0f, 0.0f, 1.0f)); + + + } + + void OnDisable() + { + GameObject.DestroyImmediate(m_Background1.normal.background); + GameObject.DestroyImmediate(m_Background2.normal.background); + GameObject.DestroyImmediate(m_Background3.normal.background); + GameObject.DestroyImmediate(m_Background4.normal.background); + } + + void CreateAndSetTexture() + { + Texture2D tmp = new Texture2D(m_Width, m_Height); + var bytes = tmp.EncodeToPNG(); + File.WriteAllBytes("Assets/UB_BokehTexture.png", bytes); + AssetDatabase.ImportAsset("Assets/UB_BokehTexture.png"); + + m_DestinationTexture = (Texture2D)AssetDatabase.LoadAssetAtPath("Assets/UB_BokehTexture.png", typeof(Texture2D)); + } + + int m_Width = 1280; + int m_Height = 720; + + void OnGUI() + { + Undo.RecordObject(this, "Lens Bokeh Texture Generator"); + + GUILayout.Label("SETTINGS", EditorStyles.boldLabel); + + m_DestinationTexture = (Texture2D)EditorGUILayout.ObjectField("Destination Texture", m_DestinationTexture, typeof(Texture2D), false); + + if (m_DestinationTexture == null) + { + GUILayout.Label("Please set or create a destination texture."); + GUILayout.BeginHorizontal(); + m_Width = Mathf.Clamp(EditorGUILayout.IntField("Width", m_Width),10, 4096); + m_Height = Mathf.Clamp(EditorGUILayout.IntField("Height", m_Height), 10, 4096); + GUILayout.EndHorizontal(); + if (GUILayout.Button("Create and set Texture")) + { + CreateAndSetTexture(); + } + } + else + { + m_PassCount = Mathf.Clamp(EditorGUILayout.IntField("Layer Count", m_PassCount), 1, 5); + GUILayout.Space(20.0f); + GUILayout.Label("LAYERS", EditorStyles.boldLabel); + m_ScrollPos = GUILayout.BeginScrollView(m_ScrollPos); + for (int i = 0; i < m_PassCount; ++i) + { + GUILayout.BeginVertical(i % 2 == 0 ? m_Background3 : m_Background1); + BokehGenerationPass p = m_BokehPasses[i]; + p.m_BokehTexture = (Texture2D)EditorGUILayout.ObjectField("Sprite Texture", p.m_BokehTexture, typeof(Texture2D), false); + p.m_MinimumSize = DoSlider("Minimum Size", p.m_MinimumSize, 20.0f, 400.0f); + p.m_MaximumSize = DoSlider("Maximum Size", p.m_MaximumSize, 20.0f, 400.0f); + p.m_BlurRadius = DoSlider("Blur Radius", p.m_BlurRadius, 0.0f, 10.0f); + p.m_VignettePower = DoSlider("Vignette Power", p.m_VignettePower, 0.0f, 10.0f); + p.m_HueVariation = DoSlider("Hue Variation", p.m_HueVariation, 0.0f, 0.8f); + p.m_MinIntensity = DoSlider("Minimum Intensity", p.m_MinIntensity, 0.0f, 1.0f); + p.m_MaxIntensity = DoSlider("Maximum Intensity", p.m_MaxIntensity, 0.0f, 1.0f); + p.m_Density = DoSlider("Density", p.m_Density, 0.0f, 1.0f); + p.m_ChromaticAberration = DoSlider("Chromatic Aberration", p.m_ChromaticAberration, 0.0f, 50.0f); + p.m_RandomRotation = EditorGUILayout.Toggle("Random Rotation", p.m_RandomRotation); + GUILayout.Space(20.0f); + GUILayout.EndVertical(); + } + GUILayout.EndScrollView(); + + + + + if (GUILayout.Button("Generate Bokeh Texture")) + { + GenerateTexture(); + } + + if (m_DestinationTexture != null) + { + GUILayout.BeginVertical(m_Background4); + + float w = m_DestinationTexture.width; + if (m_DestinationTexture.width > 300.0f) + w = 300.0f; + + float h = ((float)m_DestinationTexture.height / (float)m_DestinationTexture.width) * w; + + Rect r = GUILayoutUtility.GetRect(w, h); + + + r.position = new Vector2(r.width * 0.5f - w*0.5f, r.position.y); + + r.height = h; + r.width = w; + + //Debug.Log("r=" + h); + EditorGUI.DrawPreviewTexture(r, m_DestinationTexture); + + GUILayout.EndVertical(); + } + + + } + + + + if (GUI.changed) + { + EditorUtility.SetDirty(this); + } + } + + float DoSlider(string label, float value, float min, float max) + { + float v = value; + EditorGUILayout.BeginHorizontal(); + v = Mathf.Clamp(EditorGUILayout.FloatField(label, v), min, max); + v = GUILayout.HorizontalSlider(v, min, max); + EditorGUILayout.EndHorizontal(); + + return v; + } + + Material m_MixerMaterial = null; + + void GenerateTexture() + { + for (int i = 0; i < m_Positions.Length; ++i) + { + m_Positions[i] = new List(); + m_MinimumDistance[i] = 1.0f; + } + + Material bokehMaterial = new Material(Shader.Find("Hidden/Ultimate/BokehTexture")); + bokehMaterial.hideFlags = HideFlags.HideAndDontSave; + + Material blurMaterial = new Material(Shader.Find("Hidden/Ultimate/Sampling")); + blurMaterial.hideFlags = HideFlags.HideAndDontSave; + + Material miscMaterial = new Material(Shader.Find("Hidden/Ultimate/BokehMisc")); + miscMaterial.hideFlags = HideFlags.HideAndDontSave; + + Material mixerMaterial = new Material(Shader.Find("Hidden/Ultimate/BloomMixer")); + mixerMaterial.hideFlags = HideFlags.HideAndDontSave; + + m_MixerMaterial = mixerMaterial; + + RenderTexture accumulation = null; + for (int i = 0; i < m_PassCount; ++i) + { + RenderTexture current = GenerateTexture(i, bokehMaterial, blurMaterial, miscMaterial, m_DestinationTexture.width, m_DestinationTexture.height, m_BokehPasses[i]); + if (accumulation == null && current != null) + accumulation = current; + else if (current != null) + { + RenderTextureAdditive(current, accumulation, 1.0f); + RenderTexture.ReleaseTemporary(current); + } + } + + + string path = AssetDatabase.GetAssetPath(m_DestinationTexture); + + Texture2D newTexture = new Texture2D(m_DestinationTexture.width, m_DestinationTexture.height); + + RenderTexture.active = accumulation; + newTexture.ReadPixels(new Rect(0, 0, newTexture.width, newTexture.height), 0, 0); + newTexture.Apply(); + + var bytes = newTexture.EncodeToPNG(); + File.WriteAllBytes(path, bytes); + AssetDatabase.ImportAsset(path); + + GameObject.DestroyImmediate(bokehMaterial); + GameObject.DestroyImmediate(miscMaterial); + GameObject.DestroyImmediate(mixerMaterial); + + + } + + private RenderTexture GenerateTexture(int idx, Material material, Material blurMaterial, Material miscMaterial,int width, int height, BokehGenerationPass p) + { + RenderTexture rtA = RenderTexture.GetTemporary(width, height); + //RenderTexture lastActive = RenderTexture.active; + + material.mainTexture = p.m_BokehTexture; + + RenderTexture.active = rtA; + GL.Clear(true, true, Color.black); + + + //GL.LoadPixelMatrix(0,width,0,height); + //GL.LoadPixelMatrix(0, width, 0, height); + Matrix4x4 proj = Matrix4x4.Ortho(0, width, 0, height, -1.0f, 1.0f); + + material.SetMatrix("_MeshProjectionMatrix", proj); + + int nbPixel = width * height; + int nbQuad = (int)(p.m_Density * 0.0004f * nbPixel); + material.SetFloat("_Intensity", UnityEngine.Random.Range( p.m_MinIntensity, p.m_MaxIntensity) ); + + float cellSize = Mathf.Max( Mathf.Sqrt(nbQuad), 0.1f); + + float xStep = (float)width / cellSize; + float yStep = (float)height / cellSize; + + for (float i = 0; i < width; i += xStep) + { + for (float j = 0; j < height; j += yStep) + { + + Color tint = new Color(UnityEngine.Random.Range(1.0f - p.m_HueVariation, 1.0f), UnityEngine.Random.Range(1.0f - p.m_HueVariation, 1.0f), UnityEngine.Random.Range(1.0f - p.m_HueVariation, 1.0f)); + material.SetColor("_Tint", tint); + material.SetPass(0); + float size = UnityEngine.Random.Range(p.m_MinimumSize, p.m_MaximumSize); + + //float x = UnityEngine.Random.Range(-1f, 1f); + //float y = UnityEngine.Random.Range(-1f, 1f); + + + float x = (i + UnityEngine.Random.Range(0, xStep)) / width * 2.0f - 1.0f; + float y = (j + UnityEngine.Random.Range(0, yStep)) / height * 2.0f - 1.0f; + + float dist = new Vector2(x, y).magnitude; + float sizeMul = Mathf.Min(Mathf.Pow(dist, p.m_VignettePower), 1.0f); + + + float s = sizeMul > 0.5f ? size * sizeMul : 0.0f; + float angle = UnityEngine.Random.Range(0.0f, p.m_RandomRotation ? 360.0f : 0.0f); + Vector3 nDiv = new Vector3(1.0f / width, 1.0f / height, 0.0f); + Vector3 tl = RotateZ(new Vector3(-s, -s, 0.0f), angle); + Vector3 tr = RotateZ(new Vector3(s, -s, 0f), angle); + Vector3 br = RotateZ(new Vector3(s, s, 0f), angle); + Vector3 bl = RotateZ(new Vector3(-s, s, 0f), angle); + + tl = new Vector3(tl.x * nDiv.x, tl.y * nDiv.y, 0.0f); + tr = new Vector3(tr.x * nDiv.x, tr.y * nDiv.y, 0.0f); + br = new Vector3(br.x * nDiv.x, br.y * nDiv.y, 0.0f); + bl = new Vector3(bl.x * nDiv.x, bl.y * nDiv.y, 0.0f); + + + DrawQuad(x, y, tl, tr, br, bl); + + } + } + + if (material.SetPass(0)) + { + + /*for (int i = 0; i < nbQuad; ++i) + { + Color tint = new Color(UnityEngine.Random.Range(1.0f - p.m_HueVariation, 1.0f), UnityEngine.Random.Range(1.0f - p.m_HueVariation, 1.0f), UnityEngine.Random.Range(1.0f - p.m_HueVariation, 1.0f)); + material.SetColor("_Tint", tint); + material.SetPass(0); + float size = UnityEngine.Random.Range(p.m_MinimumSize, p.m_MaximumSize); + + //float x = UnityEngine.Random.Range(-1f, 1f); + //float y = UnityEngine.Random.Range(-1f, 1f); + + Vector3 pos = PickPosition(idx); + float x = pos.x; + float y = pos.y; + + float dist = new Vector2(x, y).magnitude; + float sizeMul = Mathf.Min(Mathf.Pow(dist, p.m_VignettePower), 1.0f); + + + float s = sizeMul > 0.5f ? size * sizeMul : 0.0f; + float angle = UnityEngine.Random.Range(0.0f, p.m_RandomRotation? 360.0f : 0.0f); + Vector3 nDiv = new Vector3(1.0f / width, 1.0f / height, 0.0f); + Vector3 tl = RotateZ(new Vector3(-s, -s, 0.0f), angle); + Vector3 tr = RotateZ(new Vector3(s, -s, 0f), angle); + Vector3 br = RotateZ(new Vector3(s, s, 0f), angle); + Vector3 bl = RotateZ(new Vector3(-s, s, 0f), angle); + + tl = new Vector3(tl.x * nDiv.x, tl.y * nDiv.y, 0.0f); + tr = new Vector3(tr.x * nDiv.x, tr.y * nDiv.y, 0.0f); + br = new Vector3(br.x * nDiv.x, br.y * nDiv.y, 0.0f); + bl = new Vector3(bl.x * nDiv.x, bl.y * nDiv.y, 0.0f); + + + DrawQuad(x, y, tl , tr , br , bl ); + }*/ + + } + + RenderTexture rtB = RenderTexture.GetTemporary(width, height); + for (int i = 0; i < 1; ++i) + { + RenderTexture.active = rtB; + blurMaterial.SetTexture("_AdditiveTexture", Texture2D.blackTexture); + blurMaterial.SetVector("_OffsetInfos", new Vector4(1.0f / width * p.m_BlurRadius, 0, 0, 0)); + blurMaterial.SetVector("_Tint", Color.white); + blurMaterial.SetFloat("_Intensity", 1.0f); + Graphics.Blit(rtA, rtB, blurMaterial, 2); + + blurMaterial.SetVector("_OffsetInfos", new Vector4(0, 1.0f / height * p.m_BlurRadius, 0, 0)); + Graphics.Blit(rtB, rtA, blurMaterial, 4); + } + + // Chromatic Aberration + miscMaterial.SetFloat("_ChromaticAberration", p.m_ChromaticAberration); + Graphics.Blit(rtA, rtB, miscMaterial, 0); + + /*RenderTexture.active = rtB; + Texture2D texture = new Texture2D(width, height); + texture.ReadPixels(new Rect(0, 0, width, height), 0, 0); + texture.Apply();*/ + + RenderTexture.ReleaseTemporary(rtA); + //RenderTexture.ReleaseTemporary(rtB); + //RenderTexture.active = lastActive; + + return rtB; + } + + Vector3 PickPosition(int idx) + { + float minDistance = m_MinimumDistance[idx]; + List positions = m_Positions[idx]; + + int nbTry = 20000; + bool ok = false; + + while (!ok) + { + float x = UnityEngine.Random.Range(-1f, 1f); + float y = UnityEngine.Random.Range(-1f, 1f); + + Vector3 pos = new Vector3(x, y, 0.0f); + + bool foundNearPos = false; + foreach (Vector3 cPos in positions) + { + if (Vector3.Distance(cPos, pos) < minDistance) + { + minDistance -= 0.1f; + m_MinimumDistance[idx] = minDistance; + foundNearPos = true; + break; + } + } + + if (!foundNearPos) + { + return pos; + } + + nbTry--; + if (nbTry < 0) + break; + } + + + + return Vector3.zero; + } + + public Vector3 RotateZ(Vector3 v, float angle) + { + float sin = Mathf.Sin(angle); + float cos = Mathf.Cos(angle); + + float tx = v.x; + float ty = v.y; + + Vector3 r = new Vector3(); + r.x = (cos * tx) - (sin * ty); + r.y = (cos * ty) + (sin * tx); + + return r; + } + + void DrawQuad(float x, float y, Vector3 tl, Vector3 tr, Vector3 br, Vector3 bl) + { + + + GL.Begin(GL.QUADS); // Quad + + GL.MultiTexCoord2(0, 1 - 0f, 0f); + GL.Vertex3(tl.x + x, tl.y + y, 0f); + + GL.MultiTexCoord2(0, 1 - 1f, 0f); + GL.Vertex3(tr.x + x, tr.y + y, 0f); + + GL.MultiTexCoord2(0, 1 - 1f, 1f); + GL.Vertex3(br.x + x, br.y + y, 0f); + + GL.MultiTexCoord2(0, 1 - 0f, 1f); + GL.Vertex3(bl.x + x, bl.y + y, 0f); + + GL.End(); + } + + /* void DrawQuad(float x, float y, float halfWidth, float halfHeight) + { + + float angle = UnityEngine.Random.Range(0.0f, 360.0f); + + + Vector3 tl = RotateZ(new Vector3(-halfWidth, -halfHeight, 0.0f), 0.0f); + Vector3 tr = RotateZ( new Vector3(halfWidth, -halfHeight, 0f), 0.0f); + Vector3 br = RotateZ(new Vector3(halfWidth, halfHeight, 0f), 0.0f); + Vector3 bl = RotateZ(new Vector3(-halfWidth, halfHeight, 0f), 0.0f); + + GL.Begin(GL.QUADS); // Quad + + GL.MultiTexCoord2(0, 1-0f, 0f); + GL.Vertex3(tl.x + x, tl.y + y, 0f); + + GL.MultiTexCoord2(0, 1 - 1f, 0f); + GL.Vertex3(tr.x + x, tr.y + y, 0f); + + GL.MultiTexCoord2(0, 1 - 1f, 1f); + GL.Vertex3(br.x + x, br.y + y, 0f); + + GL.MultiTexCoord2(0, 1 - 0f, 1f); + GL.Vertex3(bl.x + x, bl.y + y, 0f); + + GL.End(); + }*/ + + + private Texture2D MakeTex(int width, int height, Color col) + { + Color[] pix = new Color[width * height]; + + for (int i = 0; i < pix.Length; i++) + pix[i] = col; + + Texture2D result = new Texture2D(width, height); + result.hideFlags = HideFlags.HideAndDontSave; + result.SetPixels(pix); + result.Apply(); + + return result; + } + + void RenderTextureAdditive(RenderTexture source, RenderTexture destination, float intensity) + { + RenderTexture tmpTexture = RenderTexture.GetTemporary(source.width, source.height, source.depth, source.format); + Graphics.Blit(destination, tmpTexture); + + m_MixerMaterial.SetTexture("_ColorBuffer", tmpTexture); + m_MixerMaterial.SetFloat("_Intensity", intensity); + + Graphics.Blit(source, destination, m_MixerMaterial, 0); + + RenderTexture.ReleaseTemporary(tmpTexture); + } + +} diff --git a/Assets/Cinematic Effects/BloomBeta/Editor/BokehTextureGenerator.cs.meta b/Assets/Cinematic Effects/BloomBeta/Editor/BokehTextureGenerator.cs.meta new file mode 100644 index 0000000..6b35c0b --- /dev/null +++ b/Assets/Cinematic Effects/BloomBeta/Editor/BokehTextureGenerator.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: a470493edcac30948be9a852dfd59a05 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/BloomBeta/Editor/UltimateBloomEditor.cs b/Assets/Cinematic Effects/BloomBeta/Editor/UltimateBloomEditor.cs new file mode 100644 index 0000000..e0153ba --- /dev/null +++ b/Assets/Cinematic Effects/BloomBeta/Editor/UltimateBloomEditor.cs @@ -0,0 +1,445 @@ +using UnityEngine; +using System.Collections; +using UnityEditor; +using System.IO; + +[CustomEditor(typeof(UltimateBloom))] +public class UltimateBloomEditor : Editor +{ + + private Texture2D MakeTex(int width, int height, Color col) + { + Color[] pix = new Color[width * height]; + + for (int i = 0; i < pix.Length; i++) + pix[i] = col; + + Texture2D result = new Texture2D(width, height); + result.hideFlags = HideFlags.HideAndDontSave; + result.SetPixels(pix); + result.Apply(); + + return result; + } + + GUIStyle m_Background1; + GUIStyle m_Background2; + GUIStyle m_Background3; + + Texture2D m_Logo; + + public static string GetAbsoluteAssetPath(string path) + { + UltimateBloomPathLocator locator = ScriptableObject.CreateInstance(); + MonoScript script = MonoScript.FromScriptableObject(locator); + string scriptPath = AssetDatabase.GetAssetPath(script); + ScriptableObject.DestroyImmediate(locator); + return Path.GetDirectoryName(scriptPath) + "/" + path; + } + + void OnEnable() + { + m_Background1 = new GUIStyle(); + m_Background1.normal.background = MakeTex(600, 1, new Color(1.0f, 1.0f, 1.0f, 0.1f)); + m_Background2 = new GUIStyle(); + m_Background2.normal.background = MakeTex(600, 1, new Color(1.0f, 1.0f, 1.0f, 0.0f)); + m_Background3 = new GUIStyle(); + m_Background3.normal.background = MakeTex(600, 1, new Color(1.0f, 1.0f, 1.0f, 0.05f)); + + string logoPath = GetAbsoluteAssetPath("Editor/ub_logo.png"); + m_Logo = (Texture2D)AssetDatabase.LoadAssetAtPath(logoPath, typeof(Texture2D)); + + if (m_Logo != null) + m_Logo.hideFlags = HideFlags.HideAndDontSave; + } + + void OnDisable() + { + GameObject.DestroyImmediate(m_Background1.normal.background); + GameObject.DestroyImmediate(m_Background2.normal.background); + GameObject.DestroyImmediate(m_Background3.normal.background); + } + + + public override void OnInspectorGUI() + { + UltimateBloom bloomDeluxe = (UltimateBloom)target; + Undo.RecordObject(bloomDeluxe, "Bloom DELUXE"); + + if (m_Logo != null) + { + Rect rect = GUILayoutUtility.GetRect(m_Logo.width, m_Logo.height); + GUI.DrawTexture(rect, m_Logo, ScaleMode.ScaleToFit); + } + GUILayout.BeginVertical("Box"); + bloomDeluxe.m_UiShowBloomSettings = UBHelper.GroupHeader("Bloom Settings", bloomDeluxe.m_UiShowBloomSettings); + if (bloomDeluxe.m_UiShowBloomSettings) + { + + bloomDeluxe.m_HDR = (UltimateBloom.HDRBloomMode)EditorGUILayout.EnumPopup("HDR", bloomDeluxe.m_HDR); + bloomDeluxe.m_InvertImage = EditorGUILayout.Toggle("Flip Image", bloomDeluxe.m_InvertImage); + + + bloomDeluxe.m_BloomIntensity = DoSlider("Bloom Master Intensity", bloomDeluxe.m_BloomIntensity, 0.0f, 5.0f); + //bloomDeluxe.m_BloomIntensity = Mathf.Clamp(EditorGUILayout.FloatField("Bloom Master Intensity", bloomDeluxe.m_BloomIntensity), 0.0f, 100.0f); + bloomDeluxe.m_DownscaleCount = Mathf.Clamp(EditorGUILayout.IntField("Layers (Downscale Count)", bloomDeluxe.m_DownscaleCount), 1, 6); + if (GUILayout.Button((bloomDeluxe.m_UiShowBloomScales ? "Hide Layers" : "Show Layers") + "[" + bloomDeluxe.m_DownscaleCount + "]")) + bloomDeluxe.m_UiShowBloomScales = !bloomDeluxe.m_UiShowBloomScales; + + if (bloomDeluxe.m_UiShowBloomScales) + { + + for (int i = 0; i < bloomDeluxe.m_DownscaleCount; ++i) + { + GUILayout.BeginVertical(i % 2 == 0 ? m_Background3 : m_Background1); + int idx = i + 1; + bloomDeluxe.m_BloomUsages[i] = EditorGUILayout.Toggle(" Layer " + idx + " Enabled", bloomDeluxe.m_BloomUsages[i]); + bloomDeluxe.m_BloomIntensities[i] = DoSlider(" Layer " + idx + " Intensity", bloomDeluxe.m_BloomIntensities[i], 0.0f, 5.0f); + bloomDeluxe.m_BloomColors[i] = EditorGUILayout.ColorField(" Layer " + idx + " Tint", bloomDeluxe.m_BloomColors[i]); + GUILayout.EndVertical(); + } + } + GUILayout.Space(10.0f); + } + GUILayout.EndVertical(); + + // Intensity Management + GUILayout.BeginVertical("Box"); + bloomDeluxe.m_UiShowIntensity = UBHelper.GroupHeader("Intensity Settings", bloomDeluxe.m_UiShowIntensity); + if (bloomDeluxe.m_UiShowIntensity) + { + UltimateBloom.BloomIntensityManagement lastIm = bloomDeluxe.m_IntensityManagement; + bloomDeluxe.m_IntensityManagement = (UltimateBloom.BloomIntensityManagement)EditorGUILayout.EnumPopup("Intensity Function", bloomDeluxe.m_IntensityManagement); + if (bloomDeluxe.m_IntensityManagement == UltimateBloom.BloomIntensityManagement.Threshold) + { + bloomDeluxe.m_BloomThreshhold = DoSlider(" Threshold", bloomDeluxe.m_BloomThreshhold, 0.0f, 5.0f); + } + else if (bloomDeluxe.m_IntensityManagement == UltimateBloom.BloomIntensityManagement.FilmicCurve) + { + bloomDeluxe.m_BloomCurve.OnGUI(); + } + if (lastIm != bloomDeluxe.m_IntensityManagement) + bloomDeluxe.ForceShadersReload(); + GUILayout.Space(10.0f); + } + GUILayout.EndVertical(); + + // Sampling + GUILayout.BeginVertical("Box"); + bloomDeluxe.m_UiShowSampling = UBHelper.GroupHeader("Sampling", bloomDeluxe.m_UiShowSampling); + if (bloomDeluxe.m_UiShowSampling) + { + bloomDeluxe.m_TemporalStableDownsampling = EditorGUILayout.Toggle("Temporal Stability Filter", bloomDeluxe.m_TemporalStableDownsampling); + bloomDeluxe.m_SamplingMode = (UltimateBloom.SamplingMode)EditorGUILayout.EnumPopup("Sampling Mode", bloomDeluxe.m_SamplingMode); + if (bloomDeluxe.m_SamplingMode == UltimateBloom.SamplingMode.Fixed) + bloomDeluxe.m_UpsamplingQuality = (UltimateBloom.BloomSamplingQuality)EditorGUILayout.EnumPopup("Sampling Kernel Size", bloomDeluxe.m_UpsamplingQuality); + else // Screen relative sampling + { + bloomDeluxe.m_SamplingMinHeight = DoSlider("Min Height", bloomDeluxe.m_SamplingMinHeight, 300.0f, 1000.0f); + + if (GUILayout.Button((bloomDeluxe.m_UiShowHeightSampling ? "Hide Sampling Heights" : "Show Sampling Heights"))) + bloomDeluxe.m_UiShowHeightSampling = !bloomDeluxe.m_UiShowHeightSampling; + + if (bloomDeluxe.m_UiShowHeightSampling) + { + bloomDeluxe.ComputeResolutionRelativeData(); + for (int i = 0; i < bloomDeluxe.m_ResSamplingPixelCount.Length; ++i) + { + GUILayout.Label("Sampling Height[" + i + "] = " + bloomDeluxe.m_ResSamplingPixelCount[i]); + } + } + } + + GUILayout.Space(10.0f); + } + GUILayout.EndVertical(); + + // Optimizations + GUILayout.BeginVertical("Box"); + bloomDeluxe.m_UiShowOptimizations = UBHelper.GroupHeader("Optimizations", bloomDeluxe.m_UiShowOptimizations); + if (bloomDeluxe.m_UiShowOptimizations) + { + bloomDeluxe.m_DirectDownSample = EditorGUILayout.Toggle("Direct Downsampling", bloomDeluxe.m_DirectDownSample); + if (bloomDeluxe.m_DirectDownSample) + EditorGUILayout.HelpBox("Enabling direct downsampling may introduce jittering. It should only be enabled on low end hardwares.", MessageType.Info); + bloomDeluxe.m_DirectUpsample = EditorGUILayout.Toggle("Direct Upsampling", bloomDeluxe.m_DirectUpsample); + GUILayout.Space(10.0f); + } + GUILayout.EndVertical(); + + // LENS DUST + GUILayout.BeginVertical("Box"); + bloomDeluxe.m_UiShowLensDirt = UBHelper.GroupHeader("Lens Dirt", bloomDeluxe.m_UiShowLensDirt); + if (bloomDeluxe.m_UiShowLensDirt) + { + bool lastUseLensDust = bloomDeluxe.m_UseLensDust; + bloomDeluxe.m_UseLensDust = EditorGUILayout.Toggle("Use Lens Dirt", bloomDeluxe.m_UseLensDust); + if (bloomDeluxe.m_UseLensDust) + { + bloomDeluxe.m_DustTexture = (Texture2D)EditorGUILayout.ObjectField(" Dirt Texture", bloomDeluxe.m_DustTexture, typeof(Texture2D), false); + bloomDeluxe.m_DustIntensity = DoSlider(" Dirtiness", bloomDeluxe.m_DustIntensity, 0.0f, 10.0f); + bloomDeluxe.m_DirtLightIntensity = DoSlider(" Dirt Light Intensity", bloomDeluxe.m_DirtLightIntensity, 0.0f, 30.0f); + } + if (lastUseLensDust != bloomDeluxe.m_UseLensDust) + bloomDeluxe.ForceShadersReload(); + GUILayout.Space(10.0f); + } + GUILayout.EndVertical(); + + // LENS FLARE + GUILayout.BeginVertical("Box"); + bloomDeluxe.m_UiShowLensFlare = UBHelper.GroupHeader("Lens Flare (Bokeh & Ghost)", bloomDeluxe.m_UiShowLensFlare); + if (bloomDeluxe.m_UiShowLensFlare) + { + bool lastUseLensFlare = bloomDeluxe.m_UseLensFlare; + bloomDeluxe.m_UseLensFlare = EditorGUILayout.Toggle("Use Lens Flare", bloomDeluxe.m_UseLensFlare); + if (bloomDeluxe.m_UseLensFlare) + { + UltimateBloom.FlarePresets preset = (UltimateBloom.FlarePresets)EditorGUILayout.EnumPopup("Flare Preset", UltimateBloom.FlarePresets.ChoosePreset); + SetFlarePreset(preset, bloomDeluxe); + + bloomDeluxe.m_FlareRendering = (UltimateBloom.FlareRendering)EditorGUILayout.EnumPopup(" Flare Rendering", bloomDeluxe.m_FlareRendering); + if (bloomDeluxe.m_FlareRendering != UltimateBloom.FlareRendering.Sharp) + { + bloomDeluxe.m_FlareBlurQuality = (UltimateBloom.FlareBlurQuality)EditorGUILayout.EnumPopup(" Blur Quality", bloomDeluxe.m_FlareBlurQuality); + } + + UltimateBloom.FlareType lastFareType = bloomDeluxe.m_FlareType; + bloomDeluxe.m_FlareType = (UltimateBloom.FlareType)EditorGUILayout.EnumPopup(" Flare Duplication", bloomDeluxe.m_FlareType); + if (lastFareType != bloomDeluxe.m_FlareType) + bloomDeluxe.ForceShadersReload(); + + bloomDeluxe.m_FlareIntensity = DoSlider(" Flare Intensity", bloomDeluxe.m_FlareIntensity, 0.0f, 30.0f); + bloomDeluxe.m_FlareTreshold = DoSlider(" Threshold", bloomDeluxe.m_FlareTreshold, 0.0f, 5.0f); + bloomDeluxe.m_FlareGlobalScale = DoSlider(" Global Scale", bloomDeluxe.m_FlareGlobalScale, 0.1f, 5.0f); + bloomDeluxe.m_FlareScales = EditorGUILayout.Vector4Field(" Flare Scales Far", bloomDeluxe.m_FlareScales); + if (bloomDeluxe.m_FlareType == UltimateBloom.FlareType.Double) + bloomDeluxe.m_FlareScalesNear = EditorGUILayout.Vector4Field(" Flare Scales Near", bloomDeluxe.m_FlareScalesNear); + Vector4 tmp = bloomDeluxe.m_FlareScales; + float maxFlareScale = 12.0f; + bloomDeluxe.m_FlareScales = new Vector4(Mathf.Clamp(tmp.x, 0, maxFlareScale), Mathf.Clamp(tmp.y, 0, maxFlareScale), Mathf.Clamp(tmp.z, 0, maxFlareScale), Mathf.Clamp(tmp.w, 0, maxFlareScale)); + + tmp = bloomDeluxe.m_FlareScalesNear; + bloomDeluxe.m_FlareScalesNear = new Vector4(Mathf.Clamp(tmp.x, 0, maxFlareScale), Mathf.Clamp(tmp.y, 0, maxFlareScale), Mathf.Clamp(tmp.z, 0, maxFlareScale), Mathf.Clamp(tmp.w, 0, maxFlareScale)); + + bloomDeluxe.m_FlareTint0 = EditorGUILayout.ColorField(" Flare Tint 0", bloomDeluxe.m_FlareTint0); + bloomDeluxe.m_FlareTint1 = EditorGUILayout.ColorField(" Flare Tint 1", bloomDeluxe.m_FlareTint1); + bloomDeluxe.m_FlareTint2 = EditorGUILayout.ColorField(" Flare Tint 2", bloomDeluxe.m_FlareTint2); + bloomDeluxe.m_FlareTint3 = EditorGUILayout.ColorField(" Flare Tint 3", bloomDeluxe.m_FlareTint3); + + if (bloomDeluxe.m_FlareType == UltimateBloom.FlareType.Double) + { + bloomDeluxe.m_FlareTint4 = EditorGUILayout.ColorField(" Flare Tint 4", bloomDeluxe.m_FlareTint4); + bloomDeluxe.m_FlareTint5 = EditorGUILayout.ColorField(" Flare Tint 5", bloomDeluxe.m_FlareTint5); + bloomDeluxe.m_FlareTint6 = EditorGUILayout.ColorField(" Flare Tint 6", bloomDeluxe.m_FlareTint6); + bloomDeluxe.m_FlareTint7 = EditorGUILayout.ColorField(" Flare Tint 7", bloomDeluxe.m_FlareTint7); + } + + bloomDeluxe.m_FlareMask = (Texture2D)EditorGUILayout.ObjectField(" Flare Mask", bloomDeluxe.m_FlareMask, typeof(Texture2D), false); + + bloomDeluxe.m_UseBokehFlare = EditorGUILayout.Toggle("Use Bokeh Texture", bloomDeluxe.m_UseBokehFlare); + if (bloomDeluxe.m_UseBokehFlare) + { + bloomDeluxe.m_BokehFlareQuality = (UltimateBloom.BokehFlareQuality)EditorGUILayout.EnumPopup(" Bokeh Quality", bloomDeluxe.m_BokehFlareQuality); + + bloomDeluxe.m_BokehScale = Mathf.Clamp(EditorGUILayout.FloatField(" Bokeh Scale", bloomDeluxe.m_BokehScale), 0.2f, 2.5f); + bloomDeluxe.m_FlareShape = (Texture2D)EditorGUILayout.ObjectField(" Bokeh Texture", bloomDeluxe.m_FlareShape, typeof(Texture2D), false); + } + } + if (lastUseLensFlare != bloomDeluxe.m_UseLensFlare) + bloomDeluxe.ForceShadersReload(); + GUILayout.Space(10.0f); + } + GUILayout.EndVertical(); + + // Anamorphic lens flare + + GUILayout.BeginVertical("Box"); + bloomDeluxe.m_UiShowAnamorphic = UBHelper.GroupHeader("Anamorphic Lens Flare", bloomDeluxe.m_UiShowAnamorphic); + if (bloomDeluxe.m_UiShowAnamorphic) + { + bool lastUseAnamorphic = bloomDeluxe.m_UseAnamorphicFlare; + bloomDeluxe.m_UseAnamorphicFlare = EditorGUILayout.Toggle("Use Anamorphic Lens Flare", bloomDeluxe.m_UseAnamorphicFlare); + if (bloomDeluxe.m_UseAnamorphicFlare) + { + bloomDeluxe.m_AnamorphicDownscaleCount = Mathf.Clamp(EditorGUILayout.IntField(" Layers (Downscale Count)", bloomDeluxe.m_AnamorphicDownscaleCount), 1, 6); + bloomDeluxe.m_AnamorphicFlareIntensity = DoSlider(" Intensity", bloomDeluxe.m_AnamorphicFlareIntensity, 0.0f, 5.0f); + //bloomDeluxe.m_AnamorphicFlareTreshold = DoSlider(" Treshold", bloomDeluxe.m_AnamorphicFlareTreshold, 0.0f, 5.0f); + bloomDeluxe.m_AnamorphicScale = DoSlider(" Scale", bloomDeluxe.m_AnamorphicScale, 0.0f, 6.0f); + bloomDeluxe.m_AnamorphicBlurPass = Mathf.Clamp(EditorGUILayout.IntField(" Blur Pass", bloomDeluxe.m_AnamorphicBlurPass), 1, 6); + bloomDeluxe.m_AnamorphicSmallVerticalBlur = EditorGUILayout.Toggle(" Anti-jitter Pass", bloomDeluxe.m_AnamorphicSmallVerticalBlur); + bloomDeluxe.m_AnamorphicDirection = (UltimateBloom.AnamorphicDirection)EditorGUILayout.EnumPopup(" Direction", bloomDeluxe.m_AnamorphicDirection); + } + if (lastUseAnamorphic != bloomDeluxe.m_UseAnamorphicFlare) + bloomDeluxe.ForceShadersReload(); + + if (bloomDeluxe.m_UseAnamorphicFlare) + { + if (GUILayout.Button((bloomDeluxe.m_UiShowAnamorphicBloomScales ? "Hide Layers" : "Show Layers") + "[" + bloomDeluxe.m_AnamorphicDownscaleCount + "]")) + bloomDeluxe.m_UiShowAnamorphicBloomScales = !bloomDeluxe.m_UiShowAnamorphicBloomScales; + if (bloomDeluxe.m_UiShowAnamorphicBloomScales) + { + for (int i = 0; i < bloomDeluxe.m_AnamorphicDownscaleCount; ++i) + { + GUILayout.BeginVertical(i % 2 == 0 ? m_Background3 : m_Background1); + int idx = i + 1; + bloomDeluxe.m_AnamorphicBloomUsages[i] = EditorGUILayout.Toggle(" Layer " + idx + " Enabled", bloomDeluxe.m_AnamorphicBloomUsages[i]); + bloomDeluxe.m_AnamorphicBloomIntensities[i] = DoSlider(" Layer " + idx + " Intensity", bloomDeluxe.m_AnamorphicBloomIntensities[i], 0.0f, 5.0f); + bloomDeluxe.m_AnamorphicBloomColors[i] = EditorGUILayout.ColorField(" Layer " + idx + " Tint", bloomDeluxe.m_AnamorphicBloomColors[i]); + GUILayout.EndVertical(); + } + } + } + + GUILayout.Space(10.0f); + } + GUILayout.EndVertical(); + + // Star lens flare + + GUILayout.BeginVertical("Box"); + bloomDeluxe.m_UiShowStar = UBHelper.GroupHeader("Star Lens Flare", bloomDeluxe.m_UiShowStar); + if (bloomDeluxe.m_UiShowStar) + { + bool lastUseStar = bloomDeluxe.m_UseStarFlare; + bloomDeluxe.m_UseStarFlare = EditorGUILayout.Toggle("Use Star Lens Flare", bloomDeluxe.m_UseStarFlare); + if (bloomDeluxe.m_UseStarFlare) + { + bloomDeluxe.m_StarDownscaleCount = Mathf.Clamp(EditorGUILayout.IntField(" Layers (Downscale Count)", bloomDeluxe.m_StarDownscaleCount), 1, 6); + bloomDeluxe.m_StarFlareIntensity = DoSlider(" Intensity", bloomDeluxe.m_StarFlareIntensity, 0.0f, 5.0f); + //bloomDeluxe.m_StarFlareTreshol = DoSlider(" Treshold", bloomDeluxe.m_StarFlareTreshol, 0.0f, 5.0f); + bloomDeluxe.m_StarScale = DoSlider(" Scale", bloomDeluxe.m_StarScale, 0.0f, 5.0f); + bloomDeluxe.m_StarBlurPass = Mathf.Clamp(EditorGUILayout.IntField(" Blur Pass", bloomDeluxe.m_StarBlurPass), 1, 4); + } + if (lastUseStar != bloomDeluxe.m_UseStarFlare) + bloomDeluxe.ForceShadersReload(); + + if (bloomDeluxe.m_UseStarFlare) + { + if (GUILayout.Button((bloomDeluxe.m_UiShowStarBloomScales ? "Hide Layers" : "Show Layers") + "[" + bloomDeluxe.m_StarDownscaleCount + "]")) + bloomDeluxe.m_UiShowStarBloomScales = !bloomDeluxe.m_UiShowStarBloomScales; + if (bloomDeluxe.m_UiShowStarBloomScales) + { + for (int i = 0; i < bloomDeluxe.m_StarDownscaleCount; ++i) + { + GUILayout.BeginVertical(i % 2 == 0 ? m_Background3 : m_Background1); + int idx = i + 1; + bloomDeluxe.m_StarBloomUsages[i] = EditorGUILayout.Toggle(" Layer " + idx + " Enabled", bloomDeluxe.m_StarBloomUsages[i]); + bloomDeluxe.m_StarBloomIntensities[i] = DoSlider(" Layer " + idx + " Intensity", bloomDeluxe.m_StarBloomIntensities[i], 0.0f, 5.0f); + bloomDeluxe.m_StarBloomColors[i] = EditorGUILayout.ColorField(" Layer " + idx + " Tint", bloomDeluxe.m_StarBloomColors[i]); + GUILayout.EndVertical(); + } + } + } + } + GUILayout.EndVertical(); + + if (GUI.changed) + { + EditorUtility.SetDirty(target); + } + } + + + [MenuItem("Component/UltimateBloom/Add to selected camera")] + public static void AddPreset() + { + UltimateBloom ub = GetUltimateBloomObject(); + if (ub == null) + return; + + + } + + private static UltimateBloom GetUltimateBloomObject() + { + GameObject obj = Selection.activeGameObject; + if (obj == null) + return null; + if (obj.GetComponent() == null) + return null; + + return obj.AddComponent(); + } + + float DoSlider(string label, float value, float min, float max) + { + float v = value; + EditorGUILayout.BeginHorizontal(); + v = Mathf.Clamp(EditorGUILayout.FloatField(label, v, GUILayout.ExpandWidth(false)), min, max); + v = GUILayout.HorizontalSlider(v, min, max); + EditorGUILayout.EndHorizontal(); + + return v; + } + + void SetFlarePreset(UltimateBloom.FlarePresets preset, UltimateBloom ub) + { + if (preset == UltimateBloom.FlarePresets.ChoosePreset) + return; + + if (preset == UltimateBloom.FlarePresets.Bokeh2 || preset == UltimateBloom.FlarePresets.Ghost2) + { + ub.m_FlareTint0 = new Color(78 / 255.0f, 69 / 255.0f, 149.0f / 255.0f); + ub.m_FlareTint1 = new Color(36 / 255.0f, 51 / 255.0f, 141 / 255.0f); + ub.m_FlareTint2 = new Color(29 / 255.0f, 41 / 255.0f, 105 / 255.0f); + ub.m_FlareTint3 = new Color(17 / 255.0f, 22 / 255.0f, 107 / 255.0f); + ub.m_FlareTint4 = new Color(78 / 255.0f, 69 / 255.0f, 149.0f / 255.0f); + ub.m_FlareTint5 = new Color(36 / 255.0f, 51 / 255.0f, 141 / 255.0f); + ub.m_FlareTint6 = new Color(29 / 255.0f, 41 / 255.0f, 105 / 255.0f); + ub.m_FlareTint7 = new Color(17 / 255.0f, 22 / 255.0f, 107 / 255.0f); + } + else if (preset == UltimateBloom.FlarePresets.Bokeh3 || preset == UltimateBloom.FlarePresets.Ghost3) + { + ub.m_FlareTint0 = new Color(255 / 255.0f, 135 / 255.0f, 2/ 255.0f); + ub.m_FlareTint1 = new Color(255 / 255.0f, 96 / 255.0f, 1 / 255.0f); + ub.m_FlareTint2 = new Color(255 / 255.0f, 60 / 255.0f, 1 / 255.0f); + ub.m_FlareTint3 = new Color(255 / 255.0f, 12 / 255.0f, 0 / 255.0f); + ub.m_FlareTint4 = new Color(255 / 255.0f, 184 / 255.0f, 3 / 255.0f); + ub.m_FlareTint5 = new Color(255 / 255.0f, 135 / 255.0f, 2 / 255.0f); + ub.m_FlareTint6 = new Color(255 / 255.0f, 135 / 255.0f, 2 / 255.0f); + ub.m_FlareTint7 = new Color(255 / 255.0f, 96 / 255.0f, 0 / 255.0f); + } + else + { + ub.m_FlareTint0 = new Color(137 / 255.0f, 82 / 255.0f, 0 / 255.0f); + ub.m_FlareTint1 = new Color(0 / 255.0f, 63 / 255.0f, 126 / 255.0f); + ub.m_FlareTint2 = new Color(72 / 255.0f, 151 / 255.0f, 0 / 255.0f); + ub.m_FlareTint3 = new Color(114 / 255.0f, 35 / 255.0f, 0 / 255.0f); + ub.m_FlareTint4 = new Color(122 / 255.0f, 88 / 255.0f, 0 / 255.0f); + ub.m_FlareTint5 = new Color(137 / 255.0f, 71 / 255.0f, 0 / 255.0f); + ub.m_FlareTint6 = new Color(97 / 255.0f, 139 / 255.0f, 0 / 255.0f); + ub.m_FlareTint7 = new Color(40 / 255.0f, 142 / 255.0f, 0 / 255.0f); + } + + ub.m_FlareIntensity = 1.0f; + ub.m_FlareTreshold = 0.8f; + + if (preset == UltimateBloom.FlarePresets.Bokeh1 || preset == UltimateBloom.FlarePresets.Bokeh2 || preset == UltimateBloom.FlarePresets.Bokeh3) + { + ub.m_FlareScales = new Vector4(5.77f, 2.5f, 1.32f, 1.12f); + ub.m_FlareScalesNear = new Vector4(12, 7.37f, 5.3f, 4.14f); + ub.m_FlareRendering = UltimateBloom.FlareRendering.Sharp; + ub.m_UseBokehFlare = true; + + } + else + { + ub.m_FlareScales = new Vector4(1.0f, 0.6f, 0.5f, 0.4f); + ub.m_FlareScalesNear = new Vector4(1.0f, 0.8f, 0.6f, 0.5f); + ub.m_FlareBlurQuality = UltimateBloom.FlareBlurQuality.High; + ub.m_FlareRendering = UltimateBloom.FlareRendering.Blurred; + ub.m_UseBokehFlare = false; + + + if (preset == UltimateBloom.FlarePresets.GhostFast) + ub.m_FlareBlurQuality = UltimateBloom.FlareBlurQuality.Fast; + } + + } + + void ChangeQualityPreset(UltimateBloom.BloomQualityPreset newPreset) + { + + } +} diff --git a/Assets/Cinematic Effects/BloomBeta/Editor/UltimateBloomEditor.cs.meta b/Assets/Cinematic Effects/BloomBeta/Editor/UltimateBloomEditor.cs.meta new file mode 100644 index 0000000..f7aca00 --- /dev/null +++ b/Assets/Cinematic Effects/BloomBeta/Editor/UltimateBloomEditor.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 285efee97a9b0b742b510e3de78b0b38 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/BloomBeta/Graphics.meta b/Assets/Cinematic Effects/BloomBeta/Graphics.meta new file mode 100644 index 0000000..e0a7ec7 --- /dev/null +++ b/Assets/Cinematic Effects/BloomBeta/Graphics.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 7ffc125439b8b7b40bca3705f9e0a6eb +folderAsset: yes +timeCreated: 1443580217 +licenseType: Store +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/BloomBeta/Graphics/Bokeh.png b/Assets/Cinematic Effects/BloomBeta/Graphics/Bokeh.png new file mode 100644 index 0000000000000000000000000000000000000000..31f7f529477fde2390ba29511cfb8d93d5328b4c GIT binary patch literal 5477 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 b@t*+zF=ar-fuM4700000NkvXXu0mjf&7WWk literal 0 HcmV?d00001 diff --git a/Assets/Cinematic Effects/BloomBeta/Graphics/Bokeh.png.meta b/Assets/Cinematic Effects/BloomBeta/Graphics/Bokeh.png.meta new file mode 100644 index 0000000..0eae706 --- /dev/null +++ b/Assets/Cinematic Effects/BloomBeta/Graphics/Bokeh.png.meta @@ -0,0 +1,53 @@ +fileFormatVersion: 2 +guid: c689cb7ab25ee59439a73274bbcda927 +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: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + cubemapConvolution: 0 + cubemapConvolutionSteps: 8 + cubemapConvolutionExponent: 1.5 + seamlessCubemap: 0 + textureFormat: -3 + maxTextureSize: 1024 + textureSettings: + filterMode: -1 + aniso: -1 + mipBias: -1 + wrapMode: -1 + nPOTScale: 1 + lightmap: 0 + rGBM: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 1 + textureType: -1 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/BloomBeta/Graphics/BokehRound.png b/Assets/Cinematic Effects/BloomBeta/Graphics/BokehRound.png new file mode 100644 index 0000000000000000000000000000000000000000..8baa4ffb97d1a4cb9dbd3a2ec084146413f4fabb GIT binary patch literal 6370 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�_^V@M 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 literal 0 HcmV?d00001 diff --git a/Assets/Cinematic Effects/BloomBeta/Graphics/BokehRound.png.meta b/Assets/Cinematic Effects/BloomBeta/Graphics/BokehRound.png.meta new file mode 100644 index 0000000..c5d6603 --- /dev/null +++ b/Assets/Cinematic Effects/BloomBeta/Graphics/BokehRound.png.meta @@ -0,0 +1,53 @@ +fileFormatVersion: 2 +guid: d27d217d25bb6e44ca371090b6169245 +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: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + cubemapConvolution: 0 + cubemapConvolutionSteps: 8 + cubemapConvolutionExponent: 1.5 + seamlessCubemap: 0 + textureFormat: -3 + maxTextureSize: 1024 + textureSettings: + filterMode: -1 + aniso: -1 + mipBias: -1 + wrapMode: -1 + nPOTScale: 1 + lightmap: 0 + rGBM: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 1 + textureType: -1 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/BloomBeta/Graphics/Bokehround2.png b/Assets/Cinematic Effects/BloomBeta/Graphics/Bokehround2.png new file mode 100644 index 0000000000000000000000000000000000000000..da03c38a67c595bc61a37d4f4f8d2750339d5bbd GIT binary patch literal 8242 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 literal 0 HcmV?d00001 diff --git a/Assets/Cinematic Effects/BloomBeta/Graphics/Bokehround2.png.meta b/Assets/Cinematic Effects/BloomBeta/Graphics/Bokehround2.png.meta new file mode 100644 index 0000000..7364fc5 --- /dev/null +++ b/Assets/Cinematic Effects/BloomBeta/Graphics/Bokehround2.png.meta @@ -0,0 +1,53 @@ +fileFormatVersion: 2 +guid: 58c6d4ee6f7515d428df6d3f41dd1c26 +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: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + cubemapConvolution: 0 + cubemapConvolutionSteps: 8 + cubemapConvolutionExponent: 1.5 + seamlessCubemap: 0 + textureFormat: -1 + maxTextureSize: 1024 + textureSettings: + filterMode: -1 + aniso: -1 + mipBias: -1 + wrapMode: -1 + nPOTScale: 1 + lightmap: 0 + rGBM: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 1 + textureType: -1 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/BloomBeta/Graphics/FlareMask.png b/Assets/Cinematic Effects/BloomBeta/Graphics/FlareMask.png new file mode 100644 index 0000000000000000000000000000000000000000..304893777d4e14d54bb31719143268f9fdd40d84 GIT binary patch literal 6381 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 literal 0 HcmV?d00001 diff --git a/Assets/Cinematic Effects/BloomBeta/Resources/ShadersSimplified.zip.meta b/Assets/Cinematic Effects/BloomBeta/Resources/ShadersSimplified.zip.meta new file mode 100644 index 0000000..41d5f9f --- /dev/null +++ b/Assets/Cinematic Effects/BloomBeta/Resources/ShadersSimplified.zip.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 4790c2802bfcf4b4eb367eec50a925ed +timeCreated: 1456313800 +licenseType: Store +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/BloomBeta/Resources/UltimateBloomBokehMisc.shader b/Assets/Cinematic Effects/BloomBeta/Resources/UltimateBloomBokehMisc.shader new file mode 100644 index 0000000..7a39352 --- /dev/null +++ b/Assets/Cinematic Effects/BloomBeta/Resources/UltimateBloomBokehMisc.shader @@ -0,0 +1,59 @@ +Shader "Hidden/Ultimate/BokehMisc" { + Properties { + _MainTex ("Base (RGB)", 2D) = "white" {} + } + + + Subshader + { + Pass // #0 Chromatic Aberration + { + ZTest Always Cull Off ZWrite Off + Fog { Mode off } + + CGPROGRAM + + #pragma vertex vert_img + #pragma fragment frag + #pragma fragmentoption ARB_precision_hint_fastest + #include "UnityCG.cginc" + + struct v2f + { + half4 pos : SV_POSITION; + half2 uv : TEXCOORD0; + }; + + + sampler2D _MainTex; + float4 _MainTex_TexelSize; + half _ChromaticAberration; + + half4 frag(v2f i) : COLOR + { + half2 coords = i.uv; + half2 uv = i.uv; + + coords = (coords - 0.5) * 2.0; + half coordDot = dot (coords,coords); + + half2 uvG = uv - _MainTex_TexelSize.xy * _ChromaticAberration * coords * coordDot; + half4 color = tex2D (_MainTex, uv); + #if SHADER_API_D3D9 + // Work around Cg's code generation bug for D3D9 pixel shaders :( + color.g = color.g * 0.0001 + tex2D (_MainTex, uvG).g; + #else + color.g = tex2D (_MainTex, uvG).g; + #endif + + return color; + } + + ENDCG + } + + + + } + FallBack "Diffuse" +} diff --git a/Assets/Cinematic Effects/BloomBeta/Resources/UltimateBloomBokehMisc.shader.meta b/Assets/Cinematic Effects/BloomBeta/Resources/UltimateBloomBokehMisc.shader.meta new file mode 100644 index 0000000..fa19fe5 --- /dev/null +++ b/Assets/Cinematic Effects/BloomBeta/Resources/UltimateBloomBokehMisc.shader.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 25b151c9a48c18747a9c043a91bedc31 +ShaderImporter: + defaultTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/BloomBeta/Resources/UltimateBloomCombine.shader b/Assets/Cinematic Effects/BloomBeta/Resources/UltimateBloomCombine.shader new file mode 100644 index 0000000..c03d3dc --- /dev/null +++ b/Assets/Cinematic Effects/BloomBeta/Resources/UltimateBloomCombine.shader @@ -0,0 +1,337 @@ +Shader "Hidden/Ultimate/BloomCombine" { + Properties { + _MainTex ("Base (RGB)", 2D) = "black" {} + _FlareTexture ("Flare (RGB)", 2D) = "black" {} + } + + + Subshader + { + Pass + { + ZTest Always Cull Off ZWrite Off + Fog { Mode off } + + CGPROGRAM + + +#include "UnityCG.cginc" + +struct v2f +{ + half4 pos : SV_POSITION; + half2 uv : TEXCOORD0; +}; + +v2f vert( appdata_img v ) +{ + v2f o; + o.pos = mul(UNITY_MATRIX_MVP, v.vertex); + o.uv = v.texcoord.xy; + return o; +} + +// Curve mapping +half4 _Toe; +half4 _Shoulder; +half _K; +half _Crossover; +float Map(half x) +{ + float4 data; + float endAdd; + + if (x > _Crossover) + { + data = _Shoulder; + endAdd = _K; + } + else + { + data = _Toe; + endAdd = 0; + } + + + float2 numDenum = data.xy * x + data.zw; + return numDenum.x / numDenum.y + endAdd; +} + + +sampler2D _MainTex; +sampler2D _FlareTexture; +sampler2D _ColorBuffer; +sampler2D _AdditiveTexture; +sampler2D _brightTexture; +half _Intensity; +half _FlareIntensity; +half _DirtIntensity; +half _DirtLightIntensity; +half _ScreenMaxIntensity; + + +inline float ComputeLuma( float3 c ) +{ + return dot( c, fixed3(0.299, 0.587, 0.114) ); +} + + +fixed4 frag(v2f i):COLOR +{ + half4 addedbloom = tex2D(_MainTex, i.uv); + + half4 screencolor = tex2D(_ColorBuffer, float2(i.uv.x,i.uv.y)); + + half4 bloom = addedbloom; + +#ifdef ULTIMATE_BLOOM_CURVE + half intensity = dot(screencolor, half3(0.3,0.3,0.3)); + + float colLuma = ComputeLuma(x); + + //colLuma *= _uTAA_Exposure; + half bloomIntensity = x/max(1.0+colLuma,0.001); + + //half bloomIntensity = Map(intensity); + bloom *= screencolor * bloomIntensity/intensity*2000; +#endif + +#ifdef ULTIMATE_USE_FLARE + bloom += tex2D(_FlareTexture, i.uv); /* _FlareIntensity;*/ +#endif + + bloom *= _Intensity; + +#ifdef ULTIMATE_USE_DIRT + half3 dirt = tex2D(_AdditiveTexture, i.uv).rgb; + + float dirtIntensity = dot(dirt.xyz, half3(0.3,0.3,0.3)); + float bloomIntensity = dot(bloom.xyz, half3(0.3,0.3,0.3)); + float factor = saturate(bloomIntensity * dirtIntensity * _DirtIntensity); + + bloom.xyz *= (dirt*_DirtIntensity + _DirtLightIntensity*0.2); + +#endif + + + + + return bloom + screencolor; + + +} + +fixed4 fragINV(v2f i):COLOR +{ + half4 addedbloom = tex2D(_MainTex, i.uv); + + half4 screencolor = tex2D(_ColorBuffer, float2(i.uv.x,1- i.uv.y)); + + half4 bloom = _Intensity * addedbloom; + +#ifdef ULTIMATE_BLOOM_CURVE + bloom.x = Map(bloom.x); + bloom.y = Map(bloom.y); + bloom.z = Map(bloom.z); +#endif + +#ifdef ULTIMATE_USE_FLARE + + bloom += tex2D(_FlareTexture, i.uv); + + /*half3 flare = tex2D(_FlareTexture, i.uv).rgb * 40; + half3 flareIntensity = dot(half3(0.3,0.3,0.3),flare); + half flareFactor = saturate(flareIntensity ); + bloom.xyz = lerp(bloom.xyz, flare, flareFactor);*/ + + //bloom += tex2D(_FlareTexture, i.uv) * 5; +#endif + +#ifdef ULTIMATE_USE_DIRT + half3 dirt = tex2D(_AdditiveTexture, i.uv).rgb; + + float dirtIntensity = dot(dirt.xyz, half3(0.3,0.3,0.3)); + float bloomIntensity = dot(bloom.xyz, half3(0.3,0.3,0.3)); + float factor = saturate(bloomIntensity * dirtIntensity * _DirtIntensity); + + bloom.xyz *= (dirt*_DirtIntensity + _DirtLightIntensity*0.2); +#endif + + return bloom + screencolor; + +} + + + + #pragma fragmentoption ARB_precision_hint_fastest + #pragma vertex vert + #pragma fragment frag + + ENDCG + } + + Pass + { + ZTest Always Cull Off ZWrite Off + Fog { Mode off } + + CGPROGRAM + + +#include "UnityCG.cginc" + +struct v2f +{ + half4 pos : SV_POSITION; + half2 uv : TEXCOORD0; +}; + +v2f vert( appdata_img v ) +{ + v2f o; + o.pos = mul(UNITY_MATRIX_MVP, v.vertex); + o.uv = v.texcoord.xy; + return o; +} + +// Curve mapping +half4 _Toe; +half4 _Shoulder; +half _K; +half _Crossover; +float Map(half x) +{ + float4 data; + float endAdd; + + if (x > _Crossover) + { + data = _Shoulder; + endAdd = _K; + } + else + { + data = _Toe; + endAdd = 0; + } + + + float2 numDenum = data.xy * x + data.zw; + return numDenum.x / numDenum.y + endAdd; +} + + +sampler2D _MainTex; +sampler2D _FlareTexture; +sampler2D _ColorBuffer; +sampler2D _AdditiveTexture; +sampler2D _brightTexture; +half _Intensity; +half _FlareIntensity; +half _DirtIntensity; +half _DirtLightIntensity; +half _ScreenMaxIntensity; + + +inline float ComputeLuma( float3 c ) +{ + return dot( c, fixed3(0.299, 0.587, 0.114) ); +} + + +fixed4 frag(v2f i):COLOR +{ + half4 addedbloom = tex2D(_MainTex, i.uv); + + half4 screencolor = tex2D(_ColorBuffer, float2(i.uv.x,i.uv.y)); + + half4 bloom = addedbloom; + +#ifdef ULTIMATE_BLOOM_CURVE + half intensity = dot(screencolor, half3(0.3,0.3,0.3)); + + float colLuma = ComputeLuma(x); + + //colLuma *= _uTAA_Exposure; + half bloomIntensity = x/max(1.0+colLuma,0.001); + + //half bloomIntensity = Map(intensity); + bloom *= screencolor * bloomIntensity/intensity*2000; +#endif + +#ifdef ULTIMATE_USE_FLARE + bloom += tex2D(_FlareTexture, i.uv); /* _FlareIntensity;*/ +#endif + + bloom *= _Intensity; + +#ifdef ULTIMATE_USE_DIRT + half3 dirt = tex2D(_AdditiveTexture, i.uv).rgb; + + float dirtIntensity = dot(dirt.xyz, half3(0.3,0.3,0.3)); + float bloomIntensity = dot(bloom.xyz, half3(0.3,0.3,0.3)); + float factor = saturate(bloomIntensity * dirtIntensity * _DirtIntensity); + + bloom.xyz *= (dirt*_DirtIntensity + _DirtLightIntensity*0.2); + +#endif + + + + + return bloom + screencolor; + + +} + +fixed4 fragINV(v2f i):COLOR +{ + half4 addedbloom = tex2D(_MainTex, i.uv); + + half4 screencolor = tex2D(_ColorBuffer, float2(i.uv.x,1- i.uv.y)); + + half4 bloom = _Intensity * addedbloom; + +#ifdef ULTIMATE_BLOOM_CURVE + bloom.x = Map(bloom.x); + bloom.y = Map(bloom.y); + bloom.z = Map(bloom.z); +#endif + +#ifdef ULTIMATE_USE_FLARE + + bloom += tex2D(_FlareTexture, i.uv); + + /*half3 flare = tex2D(_FlareTexture, i.uv).rgb * 40; + half3 flareIntensity = dot(half3(0.3,0.3,0.3),flare); + half flareFactor = saturate(flareIntensity ); + bloom.xyz = lerp(bloom.xyz, flare, flareFactor);*/ + + //bloom += tex2D(_FlareTexture, i.uv) * 5; +#endif + +#ifdef ULTIMATE_USE_DIRT + half3 dirt = tex2D(_AdditiveTexture, i.uv).rgb; + + float dirtIntensity = dot(dirt.xyz, half3(0.3,0.3,0.3)); + float bloomIntensity = dot(bloom.xyz, half3(0.3,0.3,0.3)); + float factor = saturate(bloomIntensity * dirtIntensity * _DirtIntensity); + + bloom.xyz *= (dirt*_DirtIntensity + _DirtLightIntensity*0.2); +#endif + + return bloom + screencolor; + +} + + + + #pragma fragmentoption ARB_precision_hint_fastest + #pragma vertex vert + #pragma fragment fragINV + + ENDCG + } + } + FallBack "Diffuse" +} diff --git a/Assets/Cinematic Effects/BloomBeta/Resources/UltimateBloomCombine.shader.meta b/Assets/Cinematic Effects/BloomBeta/Resources/UltimateBloomCombine.shader.meta new file mode 100644 index 0000000..e4b0da4 --- /dev/null +++ b/Assets/Cinematic Effects/BloomBeta/Resources/UltimateBloomCombine.shader.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 481edcf7070d4ba49a3e69a7161224a5 +ShaderImporter: + defaultTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/BloomBeta/Resources/UltimateBloomCombineCore.cginc b/Assets/Cinematic Effects/BloomBeta/Resources/UltimateBloomCombineCore.cginc new file mode 100644 index 0000000..9d23080 --- /dev/null +++ b/Assets/Cinematic Effects/BloomBeta/Resources/UltimateBloomCombineCore.cginc @@ -0,0 +1,147 @@ + +#include "UnityCG.cginc" + +struct v2f +{ + half4 pos : SV_POSITION; + half2 uv : TEXCOORD0; +}; + +v2f vert( appdata_img v ) +{ + v2f o; + o.pos = mul(UNITY_MATRIX_MVP, v.vertex); + o.uv = v.texcoord.xy; + return o; +} + +// Curve mapping +half4 _Toe; +half4 _Shoulder; +half _K; +half _Crossover; +float Map(half x) +{ + float4 data; + float endAdd; + + if (x > _Crossover) + { + data = _Shoulder; + endAdd = _K; + } + else + { + data = _Toe; + endAdd = 0; + } + + + float2 numDenum = data.xy * x + data.zw; + return numDenum.x / numDenum.y + endAdd; +} + + +sampler2D _MainTex; +sampler2D _FlareTexture; +sampler2D _ColorBuffer; +sampler2D _AdditiveTexture; +sampler2D _brightTexture; +half _Intensity; +half _FlareIntensity; +half _DirtIntensity; +half _DirtLightIntensity; +half _ScreenMaxIntensity; + + +inline float ComputeLuma( float3 c ) +{ + return dot( c, fixed3(0.299, 0.587, 0.114) ); +} + + +fixed4 frag(v2f i):COLOR +{ + half4 addedbloom = tex2D(_MainTex, i.uv); + + half4 screencolor = tex2D(_ColorBuffer, float2(i.uv.x,i.uv.y)); + + half4 bloom = addedbloom; + +#ifdef ULTIMATE_BLOOM_CURVE + half intensity = dot(screencolor, half3(0.3,0.3,0.3)); + + float colLuma = ComputeLuma(x); + + //colLuma *= _uTAA_Exposure; + half bloomIntensity = x/max(1.0+colLuma,0.001); + + //half bloomIntensity = Map(intensity); + bloom *= screencolor * bloomIntensity/intensity*2000; +#endif + +#ifdef ULTIMATE_USE_FLARE + bloom += tex2D(_FlareTexture, i.uv); /* _FlareIntensity;*/ +#endif + + bloom *= _Intensity; + +#ifdef ULTIMATE_USE_DIRT + half3 dirt = tex2D(_AdditiveTexture, i.uv).rgb; + + float dirtIntensity = dot(dirt.xyz, half3(0.3,0.3,0.3)); + float bloomIntensity = dot(bloom.xyz, half3(0.3,0.3,0.3)); + float factor = saturate(bloomIntensity * dirtIntensity * _DirtIntensity); + + bloom.xyz *= (dirt*_DirtIntensity + _DirtLightIntensity*0.2); + +#endif + + + + + return bloom + screencolor; + + +} + +fixed4 fragINV(v2f i):COLOR +{ + half4 addedbloom = tex2D(_MainTex, i.uv); + + half4 screencolor = tex2D(_ColorBuffer, float2(i.uv.x,1- i.uv.y)); + + half4 bloom = _Intensity * addedbloom; + +#ifdef ULTIMATE_BLOOM_CURVE + bloom.x = Map(bloom.x); + bloom.y = Map(bloom.y); + bloom.z = Map(bloom.z); +#endif + +#ifdef ULTIMATE_USE_FLARE + + bloom += tex2D(_FlareTexture, i.uv); + + /*half3 flare = tex2D(_FlareTexture, i.uv).rgb * 40; + half3 flareIntensity = dot(half3(0.3,0.3,0.3),flare); + half flareFactor = saturate(flareIntensity ); + bloom.xyz = lerp(bloom.xyz, flare, flareFactor);*/ + + //bloom += tex2D(_FlareTexture, i.uv) * 5; +#endif + +#ifdef ULTIMATE_USE_DIRT + half3 dirt = tex2D(_AdditiveTexture, i.uv).rgb; + + float dirtIntensity = dot(dirt.xyz, half3(0.3,0.3,0.3)); + float bloomIntensity = dot(bloom.xyz, half3(0.3,0.3,0.3)); + float factor = saturate(bloomIntensity * dirtIntensity * _DirtIntensity); + + bloom.xyz *= (dirt*_DirtIntensity + _DirtLightIntensity*0.2); +#endif + + return bloom + screencolor; + +} + diff --git a/Assets/Cinematic Effects/BloomBeta/Resources/UltimateBloomCombineCore.cginc.meta b/Assets/Cinematic Effects/BloomBeta/Resources/UltimateBloomCombineCore.cginc.meta new file mode 100644 index 0000000..d4c6305 --- /dev/null +++ b/Assets/Cinematic Effects/BloomBeta/Resources/UltimateBloomCombineCore.cginc.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 8630408eab779e24fb43f1ede27bbcf2 +ShaderImporter: + defaultTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/BloomBeta/Resources/UltimateBloomCombineFlareDirt.shader b/Assets/Cinematic Effects/BloomBeta/Resources/UltimateBloomCombineFlareDirt.shader new file mode 100644 index 0000000..238aa88 --- /dev/null +++ b/Assets/Cinematic Effects/BloomBeta/Resources/UltimateBloomCombineFlareDirt.shader @@ -0,0 +1,342 @@ +Shader "Hidden/Ultimate/BloomCombineFlareDirt" { + Properties { + _MainTex ("Base (RGB)", 2D) = "black" {} + _FlareTexture ("Flare (RGB)", 2D) = "black" {} + } + + + Subshader + { + Pass + { + ZTest Always Cull Off ZWrite Off + Fog { Mode off } + + CGPROGRAM + + #define ULTIMATE_USE_FLARE + #define ULTIMATE_USE_DIRT + + +#include "UnityCG.cginc" + +struct v2f +{ + half4 pos : SV_POSITION; + half2 uv : TEXCOORD0; +}; + +v2f vert( appdata_img v ) +{ + v2f o; + o.pos = mul(UNITY_MATRIX_MVP, v.vertex); + o.uv = v.texcoord.xy; + return o; +} + +// Curve mapping +half4 _Toe; +half4 _Shoulder; +half _K; +half _Crossover; +float Map(half x) +{ + float4 data; + float endAdd; + + if (x > _Crossover) + { + data = _Shoulder; + endAdd = _K; + } + else + { + data = _Toe; + endAdd = 0; + } + + + float2 numDenum = data.xy * x + data.zw; + return numDenum.x / numDenum.y + endAdd; +} + + +sampler2D _MainTex; +sampler2D _FlareTexture; +sampler2D _ColorBuffer; +sampler2D _AdditiveTexture; +sampler2D _brightTexture; +half _Intensity; +half _FlareIntensity; +half _DirtIntensity; +half _DirtLightIntensity; +half _ScreenMaxIntensity; + + +inline float ComputeLuma( float3 c ) +{ + return dot( c, fixed3(0.299, 0.587, 0.114) ); +} + + +fixed4 frag(v2f i):COLOR +{ + half4 addedbloom = tex2D(_MainTex, i.uv); + + half4 screencolor = tex2D(_ColorBuffer, float2(i.uv.x,i.uv.y)); + + half4 bloom = addedbloom; + +#ifdef ULTIMATE_BLOOM_CURVE + half intensity = dot(screencolor, half3(0.3,0.3,0.3)); + + float colLuma = ComputeLuma(x); + + //colLuma *= _uTAA_Exposure; + half bloomIntensity = x/max(1.0+colLuma,0.001); + + //half bloomIntensity = Map(intensity); + bloom *= screencolor * bloomIntensity/intensity*2000; +#endif + +#ifdef ULTIMATE_USE_FLARE + bloom += tex2D(_FlareTexture, i.uv); /* _FlareIntensity;*/ +#endif + + bloom *= _Intensity; + +#ifdef ULTIMATE_USE_DIRT + half3 dirt = tex2D(_AdditiveTexture, i.uv).rgb; + + float dirtIntensity = dot(dirt.xyz, half3(0.3,0.3,0.3)); + float bloomIntensity = dot(bloom.xyz, half3(0.3,0.3,0.3)); + float factor = saturate(bloomIntensity * dirtIntensity * _DirtIntensity); + + bloom.xyz *= (dirt*_DirtIntensity + _DirtLightIntensity*0.2); + +#endif + + + + + return bloom + screencolor; + + +} + +fixed4 fragINV(v2f i):COLOR +{ + half4 addedbloom = tex2D(_MainTex, i.uv); + + half4 screencolor = tex2D(_ColorBuffer, float2(i.uv.x,1- i.uv.y)); + + half4 bloom = _Intensity * addedbloom; + +#ifdef ULTIMATE_BLOOM_CURVE + bloom.x = Map(bloom.x); + bloom.y = Map(bloom.y); + bloom.z = Map(bloom.z); +#endif + +#ifdef ULTIMATE_USE_FLARE + + bloom += tex2D(_FlareTexture, i.uv); + + /*half3 flare = tex2D(_FlareTexture, i.uv).rgb * 40; + half3 flareIntensity = dot(half3(0.3,0.3,0.3),flare); + half flareFactor = saturate(flareIntensity ); + bloom.xyz = lerp(bloom.xyz, flare, flareFactor);*/ + + //bloom += tex2D(_FlareTexture, i.uv) * 5; +#endif + +#ifdef ULTIMATE_USE_DIRT + half3 dirt = tex2D(_AdditiveTexture, i.uv).rgb; + + float dirtIntensity = dot(dirt.xyz, half3(0.3,0.3,0.3)); + float bloomIntensity = dot(bloom.xyz, half3(0.3,0.3,0.3)); + float factor = saturate(bloomIntensity * dirtIntensity * _DirtIntensity); + + bloom.xyz *= (dirt*_DirtIntensity + _DirtLightIntensity*0.2); +#endif + + return bloom + screencolor; + +} + + + + #pragma fragmentoption ARB_precision_hint_fastest + #pragma vertex vert + #pragma fragment frag + + ENDCG + } + + Pass + { + ZTest Always Cull Off ZWrite Off + Fog { Mode off } + + CGPROGRAM + + #define ULTIMATE_USE_FLARE + #define ULTIMATE_USE_DIRT + +#include "UnityCG.cginc" + +struct v2f +{ + half4 pos : SV_POSITION; + half2 uv : TEXCOORD0; +}; + +v2f vert( appdata_img v ) +{ + v2f o; + o.pos = mul(UNITY_MATRIX_MVP, v.vertex); + o.uv = v.texcoord.xy; + return o; +} + +// Curve mapping +half4 _Toe; +half4 _Shoulder; +half _K; +half _Crossover; +float Map(half x) +{ + float4 data; + float endAdd; + + if (x > _Crossover) + { + data = _Shoulder; + endAdd = _K; + } + else + { + data = _Toe; + endAdd = 0; + } + + + float2 numDenum = data.xy * x + data.zw; + return numDenum.x / numDenum.y + endAdd; +} + + +sampler2D _MainTex; +sampler2D _FlareTexture; +sampler2D _ColorBuffer; +sampler2D _AdditiveTexture; +sampler2D _brightTexture; +half _Intensity; +half _FlareIntensity; +half _DirtIntensity; +half _DirtLightIntensity; +half _ScreenMaxIntensity; + + +inline float ComputeLuma( float3 c ) +{ + return dot( c, fixed3(0.299, 0.587, 0.114) ); +} + + +fixed4 frag(v2f i):COLOR +{ + half4 addedbloom = tex2D(_MainTex, i.uv); + + half4 screencolor = tex2D(_ColorBuffer, float2(i.uv.x,i.uv.y)); + + half4 bloom = addedbloom; + +#ifdef ULTIMATE_BLOOM_CURVE + half intensity = dot(screencolor, half3(0.3,0.3,0.3)); + + float colLuma = ComputeLuma(x); + + //colLuma *= _uTAA_Exposure; + half bloomIntensity = x/max(1.0+colLuma,0.001); + + //half bloomIntensity = Map(intensity); + bloom *= screencolor * bloomIntensity/intensity*2000; +#endif + +#ifdef ULTIMATE_USE_FLARE + bloom += tex2D(_FlareTexture, i.uv); /* _FlareIntensity;*/ +#endif + + bloom *= _Intensity; + +#ifdef ULTIMATE_USE_DIRT + half3 dirt = tex2D(_AdditiveTexture, i.uv).rgb; + + float dirtIntensity = dot(dirt.xyz, half3(0.3,0.3,0.3)); + float bloomIntensity = dot(bloom.xyz, half3(0.3,0.3,0.3)); + float factor = saturate(bloomIntensity * dirtIntensity * _DirtIntensity); + + bloom.xyz *= (dirt*_DirtIntensity + _DirtLightIntensity*0.2); + +#endif + + + + + return bloom + screencolor; + + +} + +fixed4 fragINV(v2f i):COLOR +{ + half4 addedbloom = tex2D(_MainTex, i.uv); + + half4 screencolor = tex2D(_ColorBuffer, float2(i.uv.x,1- i.uv.y)); + + half4 bloom = _Intensity * addedbloom; + +#ifdef ULTIMATE_BLOOM_CURVE + bloom.x = Map(bloom.x); + bloom.y = Map(bloom.y); + bloom.z = Map(bloom.z); +#endif + +#ifdef ULTIMATE_USE_FLARE + + bloom += tex2D(_FlareTexture, i.uv); + + /*half3 flare = tex2D(_FlareTexture, i.uv).rgb * 40; + half3 flareIntensity = dot(half3(0.3,0.3,0.3),flare); + half flareFactor = saturate(flareIntensity ); + bloom.xyz = lerp(bloom.xyz, flare, flareFactor);*/ + + //bloom += tex2D(_FlareTexture, i.uv) * 5; +#endif + +#ifdef ULTIMATE_USE_DIRT + half3 dirt = tex2D(_AdditiveTexture, i.uv).rgb; + + float dirtIntensity = dot(dirt.xyz, half3(0.3,0.3,0.3)); + float bloomIntensity = dot(bloom.xyz, half3(0.3,0.3,0.3)); + float factor = saturate(bloomIntensity * dirtIntensity * _DirtIntensity); + + bloom.xyz *= (dirt*_DirtIntensity + _DirtLightIntensity*0.2); +#endif + + return bloom + screencolor; + +} + + + + #pragma fragmentoption ARB_precision_hint_fastest + #pragma vertex vert + #pragma fragment fragINV + + ENDCG + } + } + FallBack "Diffuse" +} diff --git a/Assets/Cinematic Effects/BloomBeta/Resources/UltimateBloomCombineFlareDirt.shader.meta b/Assets/Cinematic Effects/BloomBeta/Resources/UltimateBloomCombineFlareDirt.shader.meta new file mode 100644 index 0000000..a407f94 --- /dev/null +++ b/Assets/Cinematic Effects/BloomBeta/Resources/UltimateBloomCombineFlareDirt.shader.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: f0ecc1337a36c4f48871c943fddaed12 +ShaderImporter: + defaultTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/BloomBeta/Resources/UltimateBloomMixer.shader b/Assets/Cinematic Effects/BloomBeta/Resources/UltimateBloomMixer.shader new file mode 100644 index 0000000..e8d87a3 --- /dev/null +++ b/Assets/Cinematic Effects/BloomBeta/Resources/UltimateBloomMixer.shader @@ -0,0 +1,108 @@ +Shader "Hidden/Ultimate/BloomMixer" { + Properties { + _MainTex ("Base (RGB)", 2D) = "white" {} + } + + + Subshader + { + Pass // #0 Blend Add + { + ZTest Always Cull Off ZWrite Off + Fog { Mode off } + + CGPROGRAM + + #pragma vertex vert_img + #pragma fragment frag + #pragma fragmentoption ARB_precision_hint_fastest + #include "UnityCG.cginc" + + struct v2f + { + half4 pos : SV_POSITION; + half2 uv : TEXCOORD0; + }; + + + sampler2D _MainTex; + sampler2D _ColorBuffer; + half _Intensity; + + fixed4 frag(v2f i):COLOR + { + half4 addedbloom = tex2D(_MainTex, i.uv); + half4 screencolor = tex2D(_ColorBuffer, i.uv); + return _Intensity * addedbloom + screencolor; + } + + ENDCG + } + + Pass // #1 Blend With Intensity + { + ZTest Always Cull Off ZWrite Off + Fog { Mode off } + + CGPROGRAM + + #pragma vertex vert_img + #pragma fragment frag + #pragma fragmentoption ARB_precision_hint_fastest + #include "UnityCG.cginc" + + struct v2f + { + half4 pos : SV_POSITION; + half2 uv : TEXCOORD0; + }; + + + sampler2D _MainTex; + sampler2D _ColorBuffer; + half _Intensity0; + half _Intensity1; + + fixed4 frag(v2f i):COLOR + { + half4 tex0 = tex2D(_MainTex, i.uv); + half4 tex1 = tex2D(_ColorBuffer, i.uv); + return tex0 * _Intensity0 + tex1 * _Intensity1; + } + + ENDCG + } + + Pass // #2 Blit with intensity + { + ZTest Always Cull Off ZWrite Off + Fog { Mode off } + + CGPROGRAM + + #pragma vertex vert_img + #pragma fragment frag + #pragma fragmentoption ARB_precision_hint_fastest + #include "UnityCG.cginc" + + struct v2f + { + half4 pos : SV_POSITION; + half2 uv : TEXCOORD0; + }; + + + sampler2D _MainTex; + half _Intensity; + + fixed4 frag(v2f i):COLOR + { + half4 tex = tex2D(_MainTex, i.uv); + return tex * _Intensity; + } + + ENDCG + } + } + FallBack "Diffuse" +} diff --git a/Assets/Cinematic Effects/BloomBeta/Resources/UltimateBloomMixer.shader.meta b/Assets/Cinematic Effects/BloomBeta/Resources/UltimateBloomMixer.shader.meta new file mode 100644 index 0000000..b943ae7 --- /dev/null +++ b/Assets/Cinematic Effects/BloomBeta/Resources/UltimateBloomMixer.shader.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 9a9192f3e87433946bcfb49c036c997d +ShaderImporter: + defaultTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/BloomBeta/Resources/UltimateBloomShader.shader b/Assets/Cinematic Effects/BloomBeta/Resources/UltimateBloomShader.shader new file mode 100644 index 0000000..4841a4d --- /dev/null +++ b/Assets/Cinematic Effects/BloomBeta/Resources/UltimateBloomShader.shader @@ -0,0 +1,488 @@ +Shader "Hidden/Ultimate/Bloom" +{ + Properties + { + _MainTex ("Base (RGB)", 2D) = "white" {} + _AdditiveTexture ("Base (RGB)", 2D) = "black" {} + _OffsetInfos ("HorizontalOffset", Vector) = (0.0,0.0,0.0,0.0) + } + + CGINCLUDE + + #pragma target 3.0 + + #include "UnityCG.cginc" + + struct v2f + { + half4 pos : SV_POSITION; + half2 uv : TEXCOORD0; + }; + + struct v2f_opts + { + half4 pos : SV_POSITION; + half2 uv[7] : TEXCOORD0; + }; + + uniform half4 _MainTex_TexelSize; + + v2f vert( appdata_img v ) + { + v2f o; + o.pos = mul(UNITY_MATRIX_MVP, v.vertex); + o.uv = v.texcoord.xy; + return o; + } + + + + float4 _OffsetInfos; + sampler2D _MainTex; + half _Intensity; + sampler2D _ColorBuffer; + sampler2D _AdditiveTexture; + sampler2D _FlareTexture; + half4 _Threshhold; + + float Gaussian(float Scale, int iSamplePoint) + { + float sigma = (Scale-1.0)/5; + float g = 1.0f / sqrt(2.0f * 3.14159 * sigma * sigma); + return (g * exp(-(iSamplePoint * iSamplePoint) / (2 * sigma * sigma))); + } + + + half4 fragGaussBlurHigh (v2f i) : SV_Target + { + half4 color = half4 (0,0,0,0); + + float Scale = 31; + + float2 gUV = i.uv; + float Offset = 0; + + color += Gaussian(Scale, 0.0 + Offset) * tex2D (_MainTex, gUV); + color += Gaussian(Scale, 1.0 + Offset) * tex2D (_MainTex, gUV + _OffsetInfos.xy * 1.0); + color += Gaussian(Scale, 1.0 + Offset) * tex2D (_MainTex, gUV - _OffsetInfos.xy * 1.0); + color += Gaussian(Scale, 2.0 + Offset) * tex2D (_MainTex, gUV + _OffsetInfos.xy * 2.0); + color += Gaussian(Scale, 2.0 + Offset) * tex2D (_MainTex, gUV - _OffsetInfos.xy * 2.0); + color += Gaussian(Scale, 3.0 + Offset) * tex2D (_MainTex, gUV + _OffsetInfos.xy * 3.0); + color += Gaussian(Scale, 3.0 + Offset) * tex2D (_MainTex, gUV - _OffsetInfos.xy * 3.0); + color += Gaussian(Scale, 4.0 + Offset) * tex2D (_MainTex, gUV + _OffsetInfos.xy * 4.0); + color += Gaussian(Scale, 4.0 + Offset) * tex2D (_MainTex, gUV - _OffsetInfos.xy * 4.0); + color += Gaussian(Scale, 5.0 + Offset) * tex2D (_MainTex, gUV + _OffsetInfos.xy * 5.0); + color += Gaussian(Scale, 5.0 + Offset) * tex2D (_MainTex, gUV - _OffsetInfos.xy * 5.0); + color += Gaussian(Scale, 6.0 + Offset) * tex2D (_MainTex, gUV + _OffsetInfos.xy * 6.0); + color += Gaussian(Scale, 6.0 + Offset) * tex2D (_MainTex, gUV - _OffsetInfos.xy * 6.0); + color += Gaussian(Scale, 7.0 + Offset) * tex2D (_MainTex, gUV + _OffsetInfos.xy * 7.0); + color += Gaussian(Scale, 7.0 + Offset) * tex2D (_MainTex, gUV - _OffsetInfos.xy * 7.0); + color += Gaussian(Scale, 8.0 + Offset) * tex2D (_MainTex, gUV + _OffsetInfos.xy * 8.0); + color += Gaussian(Scale, 8.0 + Offset) * tex2D (_MainTex, gUV - _OffsetInfos.xy * 8.0); + color += Gaussian(Scale, 9.0 + Offset) * tex2D (_MainTex, gUV + _OffsetInfos.xy * 9.0); + color += Gaussian(Scale, 9.0 + Offset) * tex2D (_MainTex, gUV - _OffsetInfos.xy * 9.0); + color += Gaussian(Scale, 10.0 + Offset) * tex2D (_MainTex, gUV + _OffsetInfos.xy * 10.0); + color += Gaussian(Scale, 10.0 + Offset) * tex2D (_MainTex, gUV - _OffsetInfos.xy * 10.0); + color += Gaussian(Scale, 11.0 + Offset) * tex2D (_MainTex, gUV + _OffsetInfos.xy * 11.0); + color += Gaussian(Scale, 11.0 + Offset) * tex2D (_MainTex, gUV - _OffsetInfos.xy * 11.0); + color += Gaussian(Scale, 12.0 + Offset) * tex2D (_MainTex, gUV + _OffsetInfos.xy * 12.0); + color += Gaussian(Scale, 12.0 + Offset) * tex2D (_MainTex, gUV - _OffsetInfos.xy * 12.0); + color += Gaussian(Scale, 13.0 + Offset) * tex2D (_MainTex, gUV + _OffsetInfos.xy * 13.0); + color += Gaussian(Scale, 13.0 + Offset) * tex2D (_MainTex, gUV - _OffsetInfos.xy * 13.0); + color += Gaussian(Scale, 14.0 + Offset) * tex2D (_MainTex, gUV + _OffsetInfos.xy * 14.0); + color += Gaussian(Scale, 14.0 + Offset) * tex2D (_MainTex, gUV - _OffsetInfos.xy * 14.0); + color += Gaussian(Scale, 15.0 + Offset) * tex2D (_MainTex, gUV + _OffsetInfos.xy * 15.0); + color += Gaussian(Scale, 15.0 + Offset) * tex2D (_MainTex, gUV - _OffsetInfos.xy * 15.0); + + return color + tex2D(_AdditiveTexture, i.uv); + } + + half4 fragGaussBlurMedium (v2f i) : SV_Target + { + half4 color = half4 (0,0,0,0); + + float Scale = 17; + + float2 gUV = i.uv; + float Offset = 0; + + color += Gaussian(Scale, 0.0 + Offset) * tex2D (_MainTex, gUV); + color += Gaussian(Scale, 1.0 + Offset) * tex2D (_MainTex, gUV + _OffsetInfos.xy * 1.0); + color += Gaussian(Scale, 1.0 + Offset) * tex2D (_MainTex, gUV - _OffsetInfos.xy * 1.0); + color += Gaussian(Scale, 2.0 + Offset) * tex2D (_MainTex, gUV + _OffsetInfos.xy * 2.0); + color += Gaussian(Scale, 2.0 + Offset) * tex2D (_MainTex, gUV - _OffsetInfos.xy * 2.0); + color += Gaussian(Scale, 3.0 + Offset) * tex2D (_MainTex, gUV + _OffsetInfos.xy * 3.0); + color += Gaussian(Scale, 3.0 + Offset) * tex2D (_MainTex, gUV - _OffsetInfos.xy * 3.0); + color += Gaussian(Scale, 4.0 + Offset) * tex2D (_MainTex, gUV + _OffsetInfos.xy * 4.0); + color += Gaussian(Scale, 4.0 + Offset) * tex2D (_MainTex, gUV - _OffsetInfos.xy * 4.0); + color += Gaussian(Scale, 5.0 + Offset) * tex2D (_MainTex, gUV + _OffsetInfos.xy * 5.0); + color += Gaussian(Scale, 5.0 + Offset) * tex2D (_MainTex, gUV - _OffsetInfos.xy * 5.0); + color += Gaussian(Scale, 6.0 + Offset) * tex2D (_MainTex, gUV + _OffsetInfos.xy * 6.0); + color += Gaussian(Scale, 6.0 + Offset) * tex2D (_MainTex, gUV - _OffsetInfos.xy * 6.0); + color += Gaussian(Scale, 7.0 + Offset) * tex2D (_MainTex, gUV + _OffsetInfos.xy * 7.0); + color += Gaussian(Scale, 7.0 + Offset) * tex2D (_MainTex, gUV - _OffsetInfos.xy * 7.0); + color += Gaussian(Scale, 8.0 + Offset) * tex2D (_MainTex, gUV + _OffsetInfos.xy * 8.0); + color += Gaussian(Scale, 8.0 + Offset) * tex2D (_MainTex, gUV - _OffsetInfos.xy * 8.0); + + return color + tex2D(_AdditiveTexture, i.uv); + } + + half4 fragGaussBlurLow (v2f i) : SV_Target + { + half4 color = half4 (0,0,0,0); + + float Scale = 9; + + float2 gUV = i.uv; + float Offset = 0; + + color += Gaussian(Scale, 0.0 + Offset) * tex2D (_MainTex, gUV); + color += Gaussian(Scale, 1.0 + Offset) * tex2D (_MainTex, gUV + _OffsetInfos.xy * 1.0); + color += Gaussian(Scale, 1.0 + Offset) * tex2D (_MainTex, gUV - _OffsetInfos.xy * 1.0); + color += Gaussian(Scale, 2.0 + Offset) * tex2D (_MainTex, gUV + _OffsetInfos.xy * 2.0); + color += Gaussian(Scale, 2.0 + Offset) * tex2D (_MainTex, gUV - _OffsetInfos.xy * 2.0); + color += Gaussian(Scale, 3.0 + Offset) * tex2D (_MainTex, gUV + _OffsetInfos.xy * 3.0); + color += Gaussian(Scale, 3.0 + Offset) * tex2D (_MainTex, gUV - _OffsetInfos.xy * 3.0); + color += Gaussian(Scale, 4.0 + Offset) * tex2D (_MainTex, gUV + _OffsetInfos.xy * 4.0); + color += Gaussian(Scale, 4.0 + Offset) * tex2D (_MainTex, gUV - _OffsetInfos.xy * 4.0); + + return color + tex2D(_AdditiveTexture, i.uv); + } + + ENDCG + + SubShader + { + Pass // #0 Simple Downscaling + { + ZTest Always Cull Off ZWrite Off + Fog { Mode off } + + CGPROGRAM + + #pragma vertex vert_img + #pragma fragment frag + #pragma fragmentoption ARB_precision_hint_fastest + #include "UnityCG.cginc" + + + fixed4 frag(v2f i):COLOR + { + + + float2 UV[4]; + + UV[0] = i.uv + float2(-1.0 * _OffsetInfos.x, -1.0 * _OffsetInfos.y); + UV[1] = i.uv + float2( 1.0 * _OffsetInfos.x, -1.0 * _OffsetInfos.y); + UV[2] = i.uv + float2(-1.0 * _OffsetInfos.x, 1.0 * _OffsetInfos.y); + UV[3] = i.uv + float2( 1.0 * _OffsetInfos.x, 1.0 * _OffsetInfos.y); + + + fixed4 Sample[4]; + + for(int j = 0; j < 4; ++j) + { + Sample[j] = tex2D(_MainTex, UV[j]); + } + + return (Sample[0] + Sample[1] + Sample[2] + Sample[3]) * 1.0/4; + } + + ENDCG + } + + Pass // #1 Gaussian Sampling High + { + CGPROGRAM + + #pragma fragmentoption ARB_precision_hint_fastest + #pragma exclude_renderers flash + #pragma vertex vert_img + #pragma fragment fragGaussBlurHigh + + ENDCG + } + + Pass // #2 Gaussian Sampling Medium + { + CGPROGRAM + + #pragma fragmentoption ARB_precision_hint_fastest + #pragma exclude_renderers flash + #pragma vertex vert_img + #pragma fragment fragGaussBlurMedium + + ENDCG + } + + Pass // #3 Gaussian Sampling Low + { + CGPROGRAM + + #pragma fragmentoption ARB_precision_hint_fastest + #pragma exclude_renderers flash + #pragma vertex vert_img + #pragma fragment fragGaussBlurLow + + ENDCG + } + + Pass // #4 Color Brightpass + { + ZTest Always Cull Off ZWrite Off + Fog { Mode off } + + CGPROGRAM + + #pragma vertex vert_img + #pragma fragment frag + #pragma fragmentoption ARB_precision_hint_fastest + #include "UnityCG.cginc" + + + + fixed4 frag(v2f i):COLOR + { + half4 color = tex2D(_MainTex, i.uv); + + half3 tColor = max(half3(0,0,0), color.rgb-_Threshhold.rgb); + //half intensity = dot(tColor, float3(0.212671, 0.71516, 0.072169)); + half intensity = dot(tColor, half3(0.3,0.3,0.3)); + + return color * intensity; + } + + ENDCG + } + + Pass // #5 Blend Add + { + ZTest Always Cull Off ZWrite Off + Fog { Mode off } + + CGPROGRAM + + #pragma vertex vert_img + #pragma fragment frag + #pragma fragmentoption ARB_precision_hint_fastest + #include "UnityCG.cginc" + + + + fixed4 frag(v2f i):COLOR + { + half4 addedbloom = tex2D(_MainTex, i.uv); + half4 screencolor = tex2D(_ColorBuffer, i.uv); + return _Intensity * addedbloom + screencolor; + } + + ENDCG + } + + Pass // #6 Blend Screen + { + ZTest Always Cull Off ZWrite Off + Fog { Mode off } + + CGPROGRAM + + #pragma vertex vert_img + #pragma fragment frag + #pragma fragmentoption ARB_precision_hint_fastest + #include "UnityCG.cginc" + + + fixed4 frag(v2f i):COLOR + { + half4 addedbloom = tex2D(_MainTex, i.uv); + half4 screencolor = tex2D(_ColorBuffer, i.uv); + return _Intensity * addedbloom + screencolor; + } + + ENDCG + } + + Pass // #7 Add One One + { + ZTest Always Cull Off ZWrite Off + Fog { Mode off } + + Blend One One + + CGPROGRAM + + #pragma vertex vert_img + #pragma fragment frag + #pragma fragmentoption ARB_precision_hint_fastest + #include "UnityCG.cginc" + + + fixed4 frag(v2f i):COLOR + { + half4 addedColors = tex2D(_MainTex, i.uv.xy); + return addedColors * _Intensity; + } + + ENDCG + } + + Pass // #8 Render Flare + { + ZTest Always Cull Off ZWrite Off + Fog { Mode off } + + + CGPROGRAM + + #pragma vertex vert_img + #pragma fragment frag + #pragma fragmentoption ARB_precision_hint_fastest + #include "UnityCG.cginc" + + half4 _FlareScales; + half4 _FlareTint0; + half4 _FlareTint1; + half4 _FlareTint2; + half4 _FlareTint3; + + half2 cUV(half2 uv) + { + return 2.0 * uv - float2(1.0,1.0); + } + + half2 tUV(half2 uv) + { + return (uv + float2(1.0,1.0))*0.5; + } + + fixed4 frag(v2f i):COLOR + { + half scale0 = _FlareScales.x;//1.1f; + half scale1 = _FlareScales.y;//0.95f; + half scale2 = _FlareScales.z;//0.75f; + half scale3 = _FlareScales.w;//0.55f; + + half2 flareUv = cUV(float2(1.0,1.0) - i.uv); + + float4 col0 = tex2D(_MainTex, tUV(flareUv*scale0) ) * _FlareTint0; + float4 col1 = tex2D(_MainTex, tUV(flareUv*scale1) ) * _FlareTint1; + float4 col2 = tex2D(_MainTex, tUV(flareUv*scale2) ) * _FlareTint2; + float4 col3 = tex2D(_MainTex, tUV(flareUv*scale3) ) * _FlareTint3; + + // Optional..­. + flareUv = cUV(i.uv); + float4 col4 = tex2D(_MainTex, tUV(flareUv*scale0) ) * _FlareTint0; + float4 col5 = tex2D(_MainTex, tUV(flareUv*scale1) ) * _FlareTint1; + float4 col6 = tex2D(_MainTex, tUV(flareUv*scale2) ) * _FlareTint2; + float4 col7 = tex2D(_MainTex, tUV(flareUv*scale3) ) * _FlareTint3; + + return (col0 + col1 + col2 + col3 + col4 + col5 + col6 + col7) * tex2D(_FlareTexture,i.uv); + } + + ENDCG + } + + Pass // #9 Blend Add with flares + { + ZTest Always Cull Off ZWrite Off + Fog { Mode off } + + CGPROGRAM + + #pragma vertex vert_img + #pragma fragment frag + #pragma fragmentoption ARB_precision_hint_fastest + #include "UnityCG.cginc" + + half _FlareIntensity; + + fixed4 frag(v2f i):COLOR + { + half4 addedbloom = tex2D(_MainTex, i.uv); + //half4 screencolor = tex2D(_ColorBuffer, float2(i.uv.x,1- i.uv.y)); + half4 screencolor = tex2D(_ColorBuffer, float2(i.uv.x,i.uv.y)); + half4 bloom = _Intensity * addedbloom + tex2D(_FlareTexture, i.uv) * _FlareIntensity; + + half3 dirt = tex2D(_AdditiveTexture, i.uv).rgb * bloom * 1000; + //bloom.rgb -= dirt; + return bloom + screencolor + float4(dirt,1.0) ; + } + + ENDCG + } + + Pass // #10 Complex Downscaling + { + ZTest Always Cull Off ZWrite Off + Fog { Mode off } + + CGPROGRAM + + #pragma vertex vert_img + #pragma fragment frag + #pragma fragmentoption ARB_precision_hint_fastest + #include "UnityCG.cginc" + + + fixed4 frag(v2f i):COLOR + { + + + float2 UV[9]; + + UV[0] = i.uv; + + UV[1] = i.uv + float2( -2.0 * _OffsetInfos.x, -2.0 * _OffsetInfos.y); + UV[2] = i.uv + float2( 0.0 * _OffsetInfos.x, -2.0 * _OffsetInfos.y); + UV[3] = i.uv + float2( 2.0 * _OffsetInfos.x, -2.0 * _OffsetInfos.y); + UV[4] = i.uv + float2( -2.0 * _OffsetInfos.x, 2.0 * _OffsetInfos.y); + UV[5] = i.uv + float2( 0.0 * _OffsetInfos.x, 2.0 * _OffsetInfos.y); + UV[6] = i.uv + float2( 2.0 * _OffsetInfos.x, 2.0 * _OffsetInfos.y); + UV[7] = i.uv + float2( -2.0 * _OffsetInfos.x, 0.0 * _OffsetInfos.y); + UV[8] = i.uv + float2( 2.0 * _OffsetInfos.x, 0.0 * _OffsetInfos.y); + + + fixed4 Sample[9]; + + for(int j = 0; j < 9; ++j) + { + Sample[j] = tex2D(_MainTex, UV[j]); + } + + return (Sample[0] + Sample[1] + Sample[2] + Sample[3] + Sample[4] + Sample[5] + Sample[6] + Sample[7] + Sample[8]) * 1.0/9; + } + + ENDCG + } + + Pass // #11 Blend Add with flares Inverted Source (for forward MSAA) + { + ZTest Always Cull Off ZWrite Off + Fog { Mode off } + + CGPROGRAM + + #pragma vertex vert_img + #pragma fragment frag + #pragma fragmentoption ARB_precision_hint_fastest + #include "UnityCG.cginc" + + half _FlareIntensity; + + fixed4 frag(v2f i):COLOR + { + half4 addedbloom = tex2D(_MainTex, i.uv); + half4 screencolor = tex2D(_ColorBuffer, float2(i.uv.x,1- i.uv.y)); + half4 bloom = _Intensity * addedbloom + tex2D(_FlareTexture, i.uv) * _FlareIntensity; + + half3 dirt = tex2D(_AdditiveTexture, i.uv).rgb * bloom * 1000; + return bloom + screencolor + float4(dirt,1.0) ; + } + + ENDCG + } + + } + + FallBack off +} diff --git a/Assets/Cinematic Effects/BloomBeta/Resources/UltimateBloomShader.shader.meta b/Assets/Cinematic Effects/BloomBeta/Resources/UltimateBloomShader.shader.meta new file mode 100644 index 0000000..dc4260d --- /dev/null +++ b/Assets/Cinematic Effects/BloomBeta/Resources/UltimateBloomShader.shader.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: ab676bda447e26b43b1479fa93ae8d8b +ShaderImporter: + defaultTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/BloomBeta/Resources/UltimateBokehTexture.shader b/Assets/Cinematic Effects/BloomBeta/Resources/UltimateBokehTexture.shader new file mode 100644 index 0000000..f54429f --- /dev/null +++ b/Assets/Cinematic Effects/BloomBeta/Resources/UltimateBokehTexture.shader @@ -0,0 +1,72 @@ +// Unlit alpha-blended shader. +// - no lighting +// - no lightmap support +// - no per-material color + +Shader "Hidden/Ultimate/BokehTexture" { +Properties { + _MainTex ("Base (RGB) Trans (A)", 2D) = "white" {} + + _Intensity ("Intensity", Float) = 1 +} + +SubShader { + Tags {"Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent"} + LOD 100 + + Cull Off + ZWrite Off + //Blend SrcAlpha One + Blend SrcAlpha OneMinusSrcAlpha + + Pass { + CGPROGRAM + #pragma vertex vert + #pragma fragment frag + #pragma target 3.0 + + #include "UnityCG.cginc" + + float4x4 _MeshProjectionMatrix; + float4x4 _MeshTransformationMatrix; + half _Intensity; + + + struct v2f { + float4 vertex : SV_POSITION; + half2 texcoord : TEXCOORD0; + }; + + sampler2D _MainTex; + float4 _MainTex_ST; + half4 _Tint; + + v2f vert (appdata_full v) + { + v2f o; + //o.vertex = mul(_MeshTransformationMatrix, v.vertex); + //o.vertex = mul(_MeshProjectionMatrix, v.vertex); + + o.vertex = v.vertex; + + o.texcoord = v.texcoord; + + + return o; + } + + fixed4 frag (v2f i) : SV_Target + { + fixed4 col = tex2D(_MainTex, i.texcoord); + + + col.xyz *= _Tint; + col.a *= _Intensity; + + return col; + } + ENDCG + } +} + +} diff --git a/Assets/Cinematic Effects/BloomBeta/Resources/UltimateBokehTexture.shader.meta b/Assets/Cinematic Effects/BloomBeta/Resources/UltimateBokehTexture.shader.meta new file mode 100644 index 0000000..90ee8ef --- /dev/null +++ b/Assets/Cinematic Effects/BloomBeta/Resources/UltimateBokehTexture.shader.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 239f6fb2ba87e0147bd6ade6d10111a9 +ShaderImporter: + defaultTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/BloomBeta/Resources/UltimateBrightpassCore.cginc b/Assets/Cinematic Effects/BloomBeta/Resources/UltimateBrightpassCore.cginc new file mode 100644 index 0000000..001db58 --- /dev/null +++ b/Assets/Cinematic Effects/BloomBeta/Resources/UltimateBrightpassCore.cginc @@ -0,0 +1,44 @@ +#include "UnityCG.cginc" + +struct v2f +{ + half4 pos : SV_POSITION; + half2 uv : TEXCOORD0; +}; + +v2f vert( appdata_img v ) +{ + v2f o; + o.pos = mul(UNITY_MATRIX_MVP, v.vertex); + o.uv = v.texcoord.xy; + return o; +} + +sampler2D _MainTex; +sampler2D _MaskTex; +half4 _Threshhold; + +fixed4 frag(v2f i):COLOR +{ + half4 color = tex2D(_MainTex, i.uv); + + half3 tColor = max(half3(0,0,0), color.rgb-_Threshhold.rgb); + half intensity = dot(tColor, half3(0.3,0.3,0.3)); + + return clamp(color * intensity * tex2D(_MaskTex, i.uv).r,0,65000); +} + +fixed4 fragNOI(v2f i):COLOR +{ + half4 color = tex2D(_MainTex, i.uv); + + half3 tColor = max(half3(0,0,0), color.rgb-_Threshhold.rgb); + + return half4(tColor, 1.0) * tex2D(_MaskTex, i.uv).r; + +} + + + + + diff --git a/Assets/Cinematic Effects/BloomBeta/Resources/UltimateBrightpassCore.cginc.meta b/Assets/Cinematic Effects/BloomBeta/Resources/UltimateBrightpassCore.cginc.meta new file mode 100644 index 0000000..910ed42 --- /dev/null +++ b/Assets/Cinematic Effects/BloomBeta/Resources/UltimateBrightpassCore.cginc.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 2ced9b82dce9c754d9cbcffaee39e640 +ShaderImporter: + defaultTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/BloomBeta/Resources/UltimateBrightpassMask.shader b/Assets/Cinematic Effects/BloomBeta/Resources/UltimateBrightpassMask.shader new file mode 100644 index 0000000..731d9c9 --- /dev/null +++ b/Assets/Cinematic Effects/BloomBeta/Resources/UltimateBrightpassMask.shader @@ -0,0 +1,131 @@ +Shader "Hidden/Ultimate/BrightpassMask" { + Properties { + _MainTex ("Base (RGB)", 2D) = "white" {} + _MaskTex ("Base (RGB)", 2D) = "white" {} + } + + + Subshader + { + Pass + { + ZTest Always Cull Off ZWrite Off + Fog { Mode off } + + CGPROGRAM + + #include "UnityCG.cginc" + +struct v2f +{ + half4 pos : SV_POSITION; + half2 uv : TEXCOORD0; +}; + +v2f vert( appdata_img v ) +{ + v2f o; + o.pos = mul(UNITY_MATRIX_MVP, v.vertex); + o.uv = v.texcoord.xy; + return o; +} + +sampler2D _MainTex; +sampler2D _MaskTex; +half4 _Threshhold; + +fixed4 frag(v2f i):COLOR +{ + half4 color = tex2D(_MainTex, i.uv); + + half3 tColor = max(half3(0,0,0), color.rgb-_Threshhold.rgb); + half intensity = dot(tColor, half3(0.3,0.3,0.3)); + + return clamp(color * intensity * tex2D(_MaskTex, i.uv).r,0,65000); +} + +fixed4 fragNOI(v2f i):COLOR +{ + half4 color = tex2D(_MainTex, i.uv); + + half3 tColor = max(half3(0,0,0), color.rgb-_Threshhold.rgb); + + return half4(tColor, 1.0) * tex2D(_MaskTex, i.uv).r; + +} + + + + + + + + #pragma fragmentoption ARB_precision_hint_fastest + #pragma vertex vert + #pragma fragment frag + + ENDCG + } + + Pass + { + ZTest Always Cull Off ZWrite Off + Fog { Mode off } + + CGPROGRAM + + #include "UnityCG.cginc" + +struct v2f +{ + half4 pos : SV_POSITION; + half2 uv : TEXCOORD0; +}; + +v2f vert( appdata_img v ) +{ + v2f o; + o.pos = mul(UNITY_MATRIX_MVP, v.vertex); + o.uv = v.texcoord.xy; + return o; +} + +sampler2D _MainTex; +sampler2D _MaskTex; +half4 _Threshhold; + +fixed4 frag(v2f i):COLOR +{ + half4 color = tex2D(_MainTex, i.uv); + + half3 tColor = max(half3(0,0,0), color.rgb-_Threshhold.rgb); + half intensity = dot(tColor, half3(0.3,0.3,0.3)); + + return clamp(color * intensity * tex2D(_MaskTex, i.uv).r,0,65000); +} + +fixed4 fragNOI(v2f i):COLOR +{ + half4 color = tex2D(_MainTex, i.uv); + + half3 tColor = max(half3(0,0,0), color.rgb-_Threshhold.rgb); + + return half4(tColor, 1.0) * tex2D(_MaskTex, i.uv).r; + +} + + + + + + + + #pragma fragmentoption ARB_precision_hint_fastest + #pragma vertex vert + #pragma fragment fragNOI + + ENDCG + } + } + FallBack "Diffuse" +} diff --git a/Assets/Cinematic Effects/BloomBeta/Resources/UltimateBrightpassMask.shader.meta b/Assets/Cinematic Effects/BloomBeta/Resources/UltimateBrightpassMask.shader.meta new file mode 100644 index 0000000..0d22629 --- /dev/null +++ b/Assets/Cinematic Effects/BloomBeta/Resources/UltimateBrightpassMask.shader.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 68bd60cbcc102e3459b4065ed54e526b +ShaderImporter: + defaultTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/BloomBeta/Resources/UltimateFlareCore.cginc b/Assets/Cinematic Effects/BloomBeta/Resources/UltimateFlareCore.cginc new file mode 100644 index 0000000..7926079 --- /dev/null +++ b/Assets/Cinematic Effects/BloomBeta/Resources/UltimateFlareCore.cginc @@ -0,0 +1,95 @@ + +#include "UnityCG.cginc" + +struct v2f +{ + half4 pos : SV_POSITION; + half2 uv : TEXCOORD0; + half4 uv0 : TEXCOORD1; + half4 uv1 : TEXCOORD2; + half4 uv2 : TEXCOORD3; + half4 uv3 : TEXCOORD4; +}; + + + +sampler2D _MainTex; +sampler2D _FlareTexture; +half _Intensity; + +half4 _FlareScales; +half4 _FlareScalesNear; +half4 _FlareTint0; +half4 _FlareTint1; +half4 _FlareTint2; +half4 _FlareTint3; +half4 _FlareTint4; +half4 _FlareTint5; +half4 _FlareTint6; +half4 _FlareTint7; + +half2 cUV(half2 uv) +{ + return 2.0 * uv - float2(1.0,1.0); +} + +half2 tUV(half2 uv) +{ + return (uv + float2(1.0,1.0))*0.5; +} + +v2f vert( appdata_img v ) +{ + v2f o; + o.pos = mul(UNITY_MATRIX_MVP, v.vertex); + o.uv = v.texcoord.xy; + + half scale0 = _FlareScales.x; + half scale1 = _FlareScales.y; + half scale2 = _FlareScales.z; + half scale3 = _FlareScales.w; + + half2 flareUv = cUV(half2(1.0,1.0) - o.uv); + o.uv0.xy = tUV(flareUv*scale0); + o.uv1.xy = tUV(flareUv*scale1); + o.uv2.xy = tUV(flareUv*scale2); + o.uv3.xy = tUV(flareUv*scale3); + + half scale4 = _FlareScalesNear.x; + half scale5 = _FlareScalesNear.y; + half scale6 = _FlareScalesNear.z; + half scale7 = _FlareScalesNear.w; + + flareUv = cUV(o.uv); + o.uv0.zw = tUV(flareUv*scale4); + o.uv1.zw = tUV(flareUv*scale5); + o.uv2.zw = tUV(flareUv*scale6); + o.uv3.zw = tUV(flareUv*scale7); + + return o; +} + +fixed4 frag(v2f i):COLOR +{ + half2 flareUv = cUV(float2(1.0,1.0) - i.uv); + + float4 acc = float4(0,0,0,0); + + acc += tex2D(_MainTex, i.uv0.xy ) * _FlareTint0; + acc += tex2D(_MainTex, i.uv1.xy ) * _FlareTint1; + acc += tex2D(_MainTex, i.uv2.xy ) * _FlareTint2; + acc += tex2D(_MainTex, i.uv3.xy ) * _FlareTint3; + +#ifdef FLARE_DOUBLE + flareUv = cUV(i.uv); + + acc += tex2D(_MainTex, i.uv0.zw ) * _FlareTint4; + acc += tex2D(_MainTex, i.uv1.zw ) * _FlareTint5; + acc += tex2D(_MainTex, i.uv2.zw ) * _FlareTint6; + acc += tex2D(_MainTex, i.uv3.zw ) * _FlareTint7; +#endif + + return clamp(acc *_Intensity,0, 65000); +} + + diff --git a/Assets/Cinematic Effects/BloomBeta/Resources/UltimateFlareCore.cginc.meta b/Assets/Cinematic Effects/BloomBeta/Resources/UltimateFlareCore.cginc.meta new file mode 100644 index 0000000..70b4163 --- /dev/null +++ b/Assets/Cinematic Effects/BloomBeta/Resources/UltimateFlareCore.cginc.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 734a7bdac9cb2e64e8a8d013f9aec730 +ShaderImporter: + defaultTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/BloomBeta/Resources/UltimateFlareDouble.shader b/Assets/Cinematic Effects/BloomBeta/Resources/UltimateFlareDouble.shader new file mode 100644 index 0000000..db1b84c --- /dev/null +++ b/Assets/Cinematic Effects/BloomBeta/Resources/UltimateFlareDouble.shader @@ -0,0 +1,123 @@ +Shader "Hidden/Ultimate/FlareDouble" { + Properties { + _MainTex ("Base (RGB)", 2D) = "white" {} + } + + + Subshader + { + Pass + { + ZTest Always Cull Off ZWrite Off + Fog { Mode off } + + CGPROGRAM + + #define FLARE_DOUBLE + + +#include "UnityCG.cginc" + +struct v2f +{ + half4 pos : SV_POSITION; + half2 uv : TEXCOORD0; + half4 uv0 : TEXCOORD1; + half4 uv1 : TEXCOORD2; + half4 uv2 : TEXCOORD3; + half4 uv3 : TEXCOORD4; +}; + + + +sampler2D _MainTex; +sampler2D _FlareTexture; +half _Intensity; + +half4 _FlareScales; +half4 _FlareScalesNear; +half4 _FlareTint0; +half4 _FlareTint1; +half4 _FlareTint2; +half4 _FlareTint3; +half4 _FlareTint4; +half4 _FlareTint5; +half4 _FlareTint6; +half4 _FlareTint7; + +half2 cUV(half2 uv) +{ + return 2.0 * uv - float2(1.0,1.0); +} + +half2 tUV(half2 uv) +{ + return (uv + float2(1.0,1.0))*0.5; +} + +v2f vert( appdata_img v ) +{ + v2f o; + o.pos = mul(UNITY_MATRIX_MVP, v.vertex); + o.uv = v.texcoord.xy; + + half scale0 = _FlareScales.x; + half scale1 = _FlareScales.y; + half scale2 = _FlareScales.z; + half scale3 = _FlareScales.w; + + half2 flareUv = cUV(half2(1.0,1.0) - o.uv); + o.uv0.xy = tUV(flareUv*scale0); + o.uv1.xy = tUV(flareUv*scale1); + o.uv2.xy = tUV(flareUv*scale2); + o.uv3.xy = tUV(flareUv*scale3); + + half scale4 = _FlareScalesNear.x; + half scale5 = _FlareScalesNear.y; + half scale6 = _FlareScalesNear.z; + half scale7 = _FlareScalesNear.w; + + flareUv = cUV(o.uv); + o.uv0.zw = tUV(flareUv*scale4); + o.uv1.zw = tUV(flareUv*scale5); + o.uv2.zw = tUV(flareUv*scale6); + o.uv3.zw = tUV(flareUv*scale7); + + return o; +} + +fixed4 frag(v2f i):COLOR +{ + half2 flareUv = cUV(float2(1.0,1.0) - i.uv); + + float4 acc = float4(0,0,0,0); + + acc += tex2D(_MainTex, i.uv0.xy ) * _FlareTint0; + acc += tex2D(_MainTex, i.uv1.xy ) * _FlareTint1; + acc += tex2D(_MainTex, i.uv2.xy ) * _FlareTint2; + acc += tex2D(_MainTex, i.uv3.xy ) * _FlareTint3; + +#ifdef FLARE_DOUBLE + flareUv = cUV(i.uv); + + acc += tex2D(_MainTex, i.uv0.zw ) * _FlareTint4; + acc += tex2D(_MainTex, i.uv1.zw ) * _FlareTint5; + acc += tex2D(_MainTex, i.uv2.zw ) * _FlareTint6; + acc += tex2D(_MainTex, i.uv3.zw ) * _FlareTint7; +#endif + + return clamp(acc *_Intensity,0, 65000); +} + + + + + #pragma fragmentoption ARB_precision_hint_fastest + #pragma vertex vert + #pragma fragment frag + + ENDCG + } + } + FallBack "Diffuse" +} diff --git a/Assets/Cinematic Effects/BloomBeta/Resources/UltimateFlareDouble.shader.meta b/Assets/Cinematic Effects/BloomBeta/Resources/UltimateFlareDouble.shader.meta new file mode 100644 index 0000000..e65deab --- /dev/null +++ b/Assets/Cinematic Effects/BloomBeta/Resources/UltimateFlareDouble.shader.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 82d5870d890eb51468257e24b9f26478 +ShaderImporter: + defaultTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/BloomBeta/Resources/UltimateFlareMask.shader b/Assets/Cinematic Effects/BloomBeta/Resources/UltimateFlareMask.shader new file mode 100644 index 0000000..5dd29ee --- /dev/null +++ b/Assets/Cinematic Effects/BloomBeta/Resources/UltimateFlareMask.shader @@ -0,0 +1,52 @@ +Shader "Hidden/Ultimate/FlareMask" { + Properties { + _MainTex ("Base (RGB)", 2D) = "white" {} + _MaskTex ("Base (RGB)", 2D) = "white" {} + } + + + Subshader + { + Pass + { + ZTest Always Cull Off ZWrite Off + Fog { Mode off } + + CGPROGRAM + + #pragma fragmentoption ARB_precision_hint_fastest + #pragma vertex vert + #pragma fragment frag + + + #include "UnityCG.cginc" + + struct v2f + { + half4 pos : SV_POSITION; + half2 uv : TEXCOORD0; + }; + + v2f vert( appdata_img v ) + { + v2f o; + o.pos = mul(UNITY_MATRIX_MVP, v.vertex); + o.uv = v.texcoord.xy; + return o; + } + + sampler2D _MainTex; + sampler2D _MaskTex; + + + fixed4 frag(v2f i):COLOR + { + return tex2D(_MainTex, i.uv) * tex2D(_MaskTex, i.uv).r; + } + + ENDCG + } + + } + FallBack "Diffuse" +} diff --git a/Assets/Cinematic Effects/BloomBeta/Resources/UltimateFlareMask.shader.meta b/Assets/Cinematic Effects/BloomBeta/Resources/UltimateFlareMask.shader.meta new file mode 100644 index 0000000..217ca61 --- /dev/null +++ b/Assets/Cinematic Effects/BloomBeta/Resources/UltimateFlareMask.shader.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: b6119eaa372f3504a92a1603c0afebc8 +ShaderImporter: + defaultTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/BloomBeta/Resources/UltimateFlareMeshShader.shader b/Assets/Cinematic Effects/BloomBeta/Resources/UltimateFlareMeshShader.shader new file mode 100644 index 0000000..4390c27 --- /dev/null +++ b/Assets/Cinematic Effects/BloomBeta/Resources/UltimateFlareMeshShader.shader @@ -0,0 +1,72 @@ +// Unlit alpha-blended shader. +// - no lighting +// - no lightmap support +// - no per-material color + +Shader "Hidden/Ultimate/FlareMesh" { +Properties { + _MainTex ("Base (RGB) Trans (A)", 2D) = "black" {} + _BrightTexture ("Base (RGB) Trans (A)", 2D) = "black" {} +} + +SubShader { + Tags {"Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent"} + LOD 100 + + Cull Off + ZWrite Off + Blend SrcAlpha One + + Pass { + CGPROGRAM + #pragma vertex vert + #pragma fragment frag + #pragma target 3.0 + #pragma glsl + + #include "UnityCG.cginc" + + float4x4 _FlareProj; + half _Intensity; + + + struct v2f { + float4 vertex : SV_POSITION; + half2 texcoord : TEXCOORD0; + half3 color : TEXCOORD1; + }; + + sampler2D _MainTex; + float4 _MainTex_ST; + sampler2D _BrightTexture; + + v2f vert (appdata_full v) + { + v2f o; + //o.vertex = mul(UNITY_MATRIX_MVP, v.vertex); + o.vertex = mul(_FlareProj, v.vertex); + o.texcoord = v.texcoord; + + half3 bloom = tex2Dlod(_BrightTexture, float4(v.texcoord1.xy,0,0) ).xyz; + o.color = bloom * _Intensity; + + half intensity = dot(half3(0.3,0.3,0.3), o.color.xyz); + if (intensity < 0.001) + o.vertex = half4(-10000,-10000,0.0,1.0); + + return o; + } + + fixed4 frag (v2f i) : SV_Target + { + fixed4 col = tex2D(_MainTex, i.texcoord); + col.xyz *= i.color.xyz; + + return col; + + } + ENDCG + } +} + +} diff --git a/Assets/Cinematic Effects/BloomBeta/Resources/UltimateFlareMeshShader.shader.meta b/Assets/Cinematic Effects/BloomBeta/Resources/UltimateFlareMeshShader.shader.meta new file mode 100644 index 0000000..75cda44 --- /dev/null +++ b/Assets/Cinematic Effects/BloomBeta/Resources/UltimateFlareMeshShader.shader.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: abe4898237b1d4d49b8a3ebc0f5b4d49 +ShaderImporter: + defaultTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/BloomBeta/Resources/UltimateFlareSingle.shader b/Assets/Cinematic Effects/BloomBeta/Resources/UltimateFlareSingle.shader new file mode 100644 index 0000000..dcf776e --- /dev/null +++ b/Assets/Cinematic Effects/BloomBeta/Resources/UltimateFlareSingle.shader @@ -0,0 +1,121 @@ +Shader "Hidden/Ultimate/FlareSingle" { + Properties { + _MainTex ("Base (RGB)", 2D) = "white" {} + } + + + Subshader + { + Pass + { + ZTest Always Cull Off ZWrite Off + Fog { Mode off } + + CGPROGRAM + + +#include "UnityCG.cginc" + +struct v2f +{ + half4 pos : SV_POSITION; + half2 uv : TEXCOORD0; + half4 uv0 : TEXCOORD1; + half4 uv1 : TEXCOORD2; + half4 uv2 : TEXCOORD3; + half4 uv3 : TEXCOORD4; +}; + + + +sampler2D _MainTex; +sampler2D _FlareTexture; +half _Intensity; + +half4 _FlareScales; +half4 _FlareScalesNear; +half4 _FlareTint0; +half4 _FlareTint1; +half4 _FlareTint2; +half4 _FlareTint3; +half4 _FlareTint4; +half4 _FlareTint5; +half4 _FlareTint6; +half4 _FlareTint7; + +half2 cUV(half2 uv) +{ + return 2.0 * uv - float2(1.0,1.0); +} + +half2 tUV(half2 uv) +{ + return (uv + float2(1.0,1.0))*0.5; +} + +v2f vert( appdata_img v ) +{ + v2f o; + o.pos = mul(UNITY_MATRIX_MVP, v.vertex); + o.uv = v.texcoord.xy; + + half scale0 = _FlareScales.x; + half scale1 = _FlareScales.y; + half scale2 = _FlareScales.z; + half scale3 = _FlareScales.w; + + half2 flareUv = cUV(half2(1.0,1.0) - o.uv); + o.uv0.xy = tUV(flareUv*scale0); + o.uv1.xy = tUV(flareUv*scale1); + o.uv2.xy = tUV(flareUv*scale2); + o.uv3.xy = tUV(flareUv*scale3); + + half scale4 = _FlareScalesNear.x; + half scale5 = _FlareScalesNear.y; + half scale6 = _FlareScalesNear.z; + half scale7 = _FlareScalesNear.w; + + flareUv = cUV(o.uv); + o.uv0.zw = tUV(flareUv*scale4); + o.uv1.zw = tUV(flareUv*scale5); + o.uv2.zw = tUV(flareUv*scale6); + o.uv3.zw = tUV(flareUv*scale7); + + return o; +} + +fixed4 frag(v2f i):COLOR +{ + half2 flareUv = cUV(float2(1.0,1.0) - i.uv); + + float4 acc = float4(0,0,0,0); + + acc += tex2D(_MainTex, i.uv0.xy ) * _FlareTint0; + acc += tex2D(_MainTex, i.uv1.xy ) * _FlareTint1; + acc += tex2D(_MainTex, i.uv2.xy ) * _FlareTint2; + acc += tex2D(_MainTex, i.uv3.xy ) * _FlareTint3; + +#ifdef FLARE_DOUBLE + flareUv = cUV(i.uv); + + acc += tex2D(_MainTex, i.uv0.zw ) * _FlareTint4; + acc += tex2D(_MainTex, i.uv1.zw ) * _FlareTint5; + acc += tex2D(_MainTex, i.uv2.zw ) * _FlareTint6; + acc += tex2D(_MainTex, i.uv3.zw ) * _FlareTint7; +#endif + + return clamp(acc *_Intensity,0, 65000); +} + + + + + #pragma fragmentoption ARB_precision_hint_fastest + #pragma vertex vert + #pragma fragment frag + + ENDCG + } + } + FallBack "Diffuse" +} diff --git a/Assets/Cinematic Effects/BloomBeta/Resources/UltimateFlareSingle.shader.meta b/Assets/Cinematic Effects/BloomBeta/Resources/UltimateFlareSingle.shader.meta new file mode 100644 index 0000000..2f3c551 --- /dev/null +++ b/Assets/Cinematic Effects/BloomBeta/Resources/UltimateFlareSingle.shader.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 079e3a5c047c057468f404709ddfe3dc +ShaderImporter: + defaultTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/BloomBeta/Resources/UltimateSampling.shader b/Assets/Cinematic Effects/BloomBeta/Resources/UltimateSampling.shader new file mode 100644 index 0000000..2a1e4d3 --- /dev/null +++ b/Assets/Cinematic Effects/BloomBeta/Resources/UltimateSampling.shader @@ -0,0 +1,751 @@ +Shader "Hidden/Ultimate/Sampling" +{ + Properties + { + _MainTex ("Base (RGB)", 2D) = "white" {} + } + + CGINCLUDE + + #pragma target 3.0 + + #include "UnityCG.cginc" + + float4 _OffsetInfos; + float4 _Tint; + float _Intensity; + sampler2D _MainTex; + sampler2D _AdditiveTexture; + + struct v2f + { + half4 pos : SV_POSITION; + half2 uv : TEXCOORD0; + }; + + struct v2f_opts + { + half4 pos : SV_POSITION; + half2 uv[7] : TEXCOORD0; + }; + + v2f vert( appdata_img v ) + { + v2f o; + o.pos = mul(UNITY_MATRIX_MVP, v.vertex); + o.uv = v.texcoord.xy; + return o; + } + + struct v2fLow { + half4 pos : POSITION; + half2 uv : TEXCOORD0; + half4 uv01 : TEXCOORD1; + half4 uv23 : TEXCOORD2; + half4 uv45 : TEXCOORD3; + half4 uv67 : TEXCOORD4; + half4 uv89 : TEXCOORD5; + }; + + + v2fLow vertLow( appdata_img v ) + { + v2fLow o; + o.pos = mul(UNITY_MATRIX_MVP, v.vertex); + o.uv = v.texcoord.xy; + + o.uv01 = v.texcoord.xyxy + _OffsetInfos.xyxy * half4(1,1, -1,-1); + o.uv23 = v.texcoord.xyxy + _OffsetInfos.xyxy * half4(1,1, -1,-1) * 2; + o.uv45 = v.texcoord.xyxy + _OffsetInfos.xyxy * half4(1,1, -1,-1) * 3; + o.uv67 = v.texcoord.xyxy + _OffsetInfos.xyxy * half4(1,1, -1,-1) * 4; + o.uv89 = v.texcoord.xyxy + _OffsetInfos.xyxy * half4(1,1, -1,-1) * 5; + + return o; + } + + inline float ComputeLuma( float3 c ) + { + return dot( c, fixed3(0.299, 0.587, 0.114) ); + } + + + float Gaussian(float Scale, int iSamplePoint) + { + float sigma = (Scale-1.0)/5; + float g = 1.0f / sqrt(2.0f * 3.14159 * sigma * sigma); + return (g * exp(-(iSamplePoint * iSamplePoint) / (2 * sigma * sigma))); + } + + float4 Upsample(half2 uv) + { + half4 f0 = tex2D (_AdditiveTexture, uv + half2(_OffsetInfos.z,_OffsetInfos.w)); + half4 f1 = tex2D (_AdditiveTexture, uv + half2(-_OffsetInfos.z,_OffsetInfos.w)); + half4 f2 = tex2D (_AdditiveTexture, uv + half2(-_OffsetInfos.z,-_OffsetInfos.w)); + half4 f3 = tex2D (_AdditiveTexture, uv + half2(_OffsetInfos.z,-_OffsetInfos.w)); + + return (f0+f1+f2+f3)*0.25; + } + + + half4 fragGaussBlurVeryHigh (v2f i) : SV_Target + { + half4 color = half4 (0,0,0,0); + + float Scale = 31; + + float2 gUV = i.uv; + float Offset = 0; + + color += 0.1480461 * tex2D (_MainTex, gUV); + color += 0.1451146 * tex2D (_MainTex, gUV + _OffsetInfos.xy * 1); + color += 0.1451146 * tex2D (_MainTex, gUV - _OffsetInfos.xy * 1); + color += 0.1366637 * tex2D (_MainTex, gUV + _OffsetInfos.xy * 2); + color += 0.1366637 * tex2D (_MainTex, gUV - _OffsetInfos.xy * 2); + color += 0.1236585 * tex2D (_MainTex, gUV + _OffsetInfos.xy * 3); + color += 0.1236585 * tex2D (_MainTex, gUV - _OffsetInfos.xy * 3); + color += 0.1075035 * tex2D (_MainTex, gUV + _OffsetInfos.xy * 4); + color += 0.1075035 * tex2D (_MainTex, gUV - _OffsetInfos.xy * 4); + color += 0.08979447 * tex2D (_MainTex, gUV + _OffsetInfos.xy * 5); + color += 0.08979447 * tex2D (_MainTex, gUV - _OffsetInfos.xy * 5); + color += 0.07206175 * tex2D (_MainTex, gUV + _OffsetInfos.xy * 6); + color += 0.07206175 * tex2D (_MainTex, gUV - _OffsetInfos.xy * 6); + color += 0.05556333 * tex2D (_MainTex, gUV + _OffsetInfos.xy * 7); + color += 0.05556333 * tex2D (_MainTex, gUV - _OffsetInfos.xy * 7); + color += 0.04116233 * tex2D (_MainTex, gUV + _OffsetInfos.xy * 8); + color += 0.04116233 * tex2D (_MainTex, gUV - _OffsetInfos.xy * 8); + color += 0.02929812 * tex2D (_MainTex, gUV + _OffsetInfos.xy * 9); + color += 0.02929812 * tex2D (_MainTex, gUV - _OffsetInfos.xy * 9); + color += 0.02003586 * tex2D (_MainTex, gUV + _OffsetInfos.xy * 10); + color += 0.02003586 * tex2D (_MainTex, gUV - _OffsetInfos.xy * 10); + color += 0.01316449 * tex2D (_MainTex, gUV + _OffsetInfos.xy * 11); + color += 0.01316449 * tex2D (_MainTex, gUV - _OffsetInfos.xy * 11); + color += 0.008310529 * tex2D (_MainTex, gUV + _OffsetInfos.xy * 12); + color += 0.008310529 * tex2D (_MainTex, gUV - _OffsetInfos.xy * 12); + color += 0.005040591 * tex2D (_MainTex, gUV + _OffsetInfos.xy * 13); + color += 0.005040591 * tex2D (_MainTex, gUV - _OffsetInfos.xy * 13); + color += 0.002937396 * tex2D (_MainTex, gUV + _OffsetInfos.xy * 14); + color += 0.002937396 * tex2D (_MainTex, gUV - _OffsetInfos.xy * 14); + color += 0.001644643 * tex2D (_MainTex, gUV + _OffsetInfos.xy * 15); + color += 0.001644643 * tex2D (_MainTex, gUV - _OffsetInfos.xy * 15); + + + color.a = 1.0; + return color * _Tint * _Intensity + Upsample(i.uv); + } + + half4 fragGaussBlurHigher (v2f i) : SV_Target + { + half4 color = half4 (0,0,0,0); + + float Scale = 31; + + float2 gUV = i.uv; + float Offset = 0; + + color += 0.1562562 * tex2D (_MainTex, gUV); + color += 0.1527989 * tex2D (_MainTex, gUV + _OffsetInfos.xy * 1); + color += 0.1527989 * tex2D (_MainTex, gUV - _OffsetInfos.xy * 1); + color += 0.1428793 * tex2D (_MainTex, gUV + _OffsetInfos.xy * 2); + color += 0.1428793 * tex2D (_MainTex, gUV - _OffsetInfos.xy * 2); + color += 0.1277568 * tex2D (_MainTex, gUV + _OffsetInfos.xy * 3); + color += 0.1277568 * tex2D (_MainTex, gUV - _OffsetInfos.xy * 3); + color += 0.1092358 * tex2D (_MainTex, gUV + _OffsetInfos.xy * 4); + color += 0.1092358 * tex2D (_MainTex, gUV - _OffsetInfos.xy * 4); + color += 0.08931243 * tex2D (_MainTex, gUV + _OffsetInfos.xy * 5); + color += 0.08931243 * tex2D (_MainTex, gUV - _OffsetInfos.xy * 5); + color += 0.06982721 * tex2D (_MainTex, gUV + _OffsetInfos.xy * 6); + color += 0.06982721 * tex2D (_MainTex, gUV - _OffsetInfos.xy * 6); + color += 0.05220396 * tex2D (_MainTex, gUV + _OffsetInfos.xy * 7); + color += 0.05220396 * tex2D (_MainTex, gUV - _OffsetInfos.xy * 7); + color += 0.03732055 * tex2D (_MainTex, gUV + _OffsetInfos.xy * 8); + color += 0.03732055 * tex2D (_MainTex, gUV - _OffsetInfos.xy * 8); + color += 0.02551284 * tex2D (_MainTex, gUV + _OffsetInfos.xy * 9); + color += 0.02551284 * tex2D (_MainTex, gUV - _OffsetInfos.xy * 9); + color += 0.01667767 * tex2D (_MainTex, gUV + _OffsetInfos.xy * 10); + color += 0.01667767 * tex2D (_MainTex, gUV - _OffsetInfos.xy * 10); + color += 0.01042505 * tex2D (_MainTex, gUV + _OffsetInfos.xy * 11); + color += 0.01042505 * tex2D (_MainTex, gUV - _OffsetInfos.xy * 11); + color += 0.006231415 * tex2D (_MainTex, gUV + _OffsetInfos.xy * 12); + color += 0.006231415 * tex2D (_MainTex, gUV - _OffsetInfos.xy * 12); + color += 0.003561732 * tex2D (_MainTex, gUV + _OffsetInfos.xy * 13); + color += 0.003561732 * tex2D (_MainTex, gUV - _OffsetInfos.xy * 13); + + + color.a = 1.0; + return color * _Tint * _Intensity + Upsample(i.uv); + } + + half4 fragGaussBlurHigh (v2f i) : SV_Target + { + half4 color = half4 (0,0,0,0); + + float Scale = 31; + + float2 gUV = i.uv; + float Offset = 0; + + color += 0.1820341 * tex2D (_MainTex, gUV); + color += 0.1764335 * tex2D (_MainTex, gUV + _OffsetInfos.xy * 1); + color += 0.1764335 * tex2D (_MainTex, gUV - _OffsetInfos.xy * 1); + color += 0.1606445 * tex2D (_MainTex, gUV + _OffsetInfos.xy * 2); + color += 0.1606445 * tex2D (_MainTex, gUV - _OffsetInfos.xy * 2); + color += 0.1374065 * tex2D (_MainTex, gUV + _OffsetInfos.xy * 3); + color += 0.1374065 * tex2D (_MainTex, gUV - _OffsetInfos.xy * 3); + color += 0.1104092 * tex2D (_MainTex, gUV + _OffsetInfos.xy * 4); + color += 0.1104092 * tex2D (_MainTex, gUV - _OffsetInfos.xy * 4); + color += 0.08334126 * tex2D (_MainTex, gUV + _OffsetInfos.xy * 5); + color += 0.08334126 * tex2D (_MainTex, gUV - _OffsetInfos.xy * 5); + color += 0.05909781 * tex2D (_MainTex, gUV + _OffsetInfos.xy * 6); + color += 0.05909781 * tex2D (_MainTex, gUV - _OffsetInfos.xy * 6); + color += 0.03936763 * tex2D (_MainTex, gUV + _OffsetInfos.xy * 7); + color += 0.03936763 * tex2D (_MainTex, gUV - _OffsetInfos.xy * 7); + color += 0.02463563 * tex2D (_MainTex, gUV + _OffsetInfos.xy * 8); + color += 0.02463563 * tex2D (_MainTex, gUV - _OffsetInfos.xy * 8); + color += 0.01448254 * tex2D (_MainTex, gUV + _OffsetInfos.xy * 9); + color += 0.01448254 * tex2D (_MainTex, gUV - _OffsetInfos.xy * 9); + color += 0.007998019 * tex2D (_MainTex, gUV + _OffsetInfos.xy * 10); + color += 0.007998019 * tex2D (_MainTex, gUV - _OffsetInfos.xy * 10); + color += 0.004149318 * tex2D (_MainTex, gUV + _OffsetInfos.xy * 11); + color += 0.004149318 * tex2D (_MainTex, gUV - _OffsetInfos.xy * 11); + + + color.a = 1.0; + return color * _Tint * _Intensity + Upsample(i.uv); + } + + half4 fragGaussBlurMedium (v2f i) : SV_Target + { + half4 color = half4 (0,0,0,0); + + float Scale = 17; + + float2 gUV = i.uv; + float Offset = 0; + + color += 0.2605744 * tex2D (_MainTex, gUV); + color += 0.242882 * tex2D (_MainTex, gUV + _OffsetInfos.xy * 1); + color += 0.242882 * tex2D (_MainTex, gUV - _OffsetInfos.xy * 1); + color += 0.1966919 * tex2D (_MainTex, gUV + _OffsetInfos.xy * 2); + color += 0.1966919 * tex2D (_MainTex, gUV - _OffsetInfos.xy * 2); + color += 0.13839 * tex2D (_MainTex, gUV + _OffsetInfos.xy * 3); + color += 0.13839 * tex2D (_MainTex, gUV - _OffsetInfos.xy * 3); + color += 0.08459612 * tex2D (_MainTex, gUV + _OffsetInfos.xy * 4); + color += 0.08459612 * tex2D (_MainTex, gUV - _OffsetInfos.xy * 4); + color += 0.04492867 * tex2D (_MainTex, gUV + _OffsetInfos.xy * 5); + color += 0.04492867 * tex2D (_MainTex, gUV - _OffsetInfos.xy * 5); + color += 0.02073118 * tex2D (_MainTex, gUV + _OffsetInfos.xy * 6); + color += 0.02073118 * tex2D (_MainTex, gUV - _OffsetInfos.xy * 6); + color += 0.008310967 * tex2D (_MainTex, gUV + _OffsetInfos.xy * 7); + color += 0.008310967 * tex2D (_MainTex, gUV - _OffsetInfos.xy * 7); + color += 0.002894721 * tex2D (_MainTex, gUV + _OffsetInfos.xy * 8); + color += 0.002894721 * tex2D (_MainTex, gUV - _OffsetInfos.xy * 8); + + + return color * _Tint * _Intensity + Upsample(i.uv); + } + + half4 fragGaussBlurLow (v2f i) : SV_Target + { + half4 color = half4 (0,0,0,0); + + float Scale = 17; + + float2 gUV = i.uv; + float Offset = 0; + + color += 0.3098615 * tex2D (_MainTex, gUV); + color += 0.2789662 * tex2D (_MainTex, gUV + _OffsetInfos.xy * 1); + color += 0.2789662 * tex2D (_MainTex, gUV - _OffsetInfos.xy * 1); + color += 0.2035652 * tex2D (_MainTex, gUV + _OffsetInfos.xy * 2); + color += 0.2035652 * tex2D (_MainTex, gUV - _OffsetInfos.xy * 2); + color += 0.1203992 * tex2D (_MainTex, gUV + _OffsetInfos.xy * 3); + color += 0.1203992 * tex2D (_MainTex, gUV - _OffsetInfos.xy * 3); + color += 0.05771804 * tex2D (_MainTex, gUV + _OffsetInfos.xy * 4); + color += 0.05771804 * tex2D (_MainTex, gUV - _OffsetInfos.xy * 4); + color += 0.02242682 * tex2D (_MainTex, gUV + _OffsetInfos.xy * 5); + color += 0.02242682 * tex2D (_MainTex, gUV - _OffsetInfos.xy * 5); + color += 0.00706304 * tex2D (_MainTex, gUV + _OffsetInfos.xy * 6); + color += 0.00706304 * tex2D (_MainTex, gUV - _OffsetInfos.xy * 6); + + + return color * _Tint * _Intensity + Upsample(i.uv); + } + + half4 fragGaussBlurVeryLow (v2fLow i) : SV_Target + { + half4 color = half4 (0,0,0,0); + + float2 gUV = i.uv; + float Offset = 0; + + color += 0.4310208 * tex2D (_MainTex, i.uv); + + color += 0.3403002 * tex2D (_MainTex, i.uv01.xy); + color += 0.3403002 * tex2D (_MainTex, i.uv01.zw); + + color += 0.1674766 * tex2D (_MainTex, i.uv23.xy); + color += 0.1674766 * tex2D (_MainTex, i.uv23.zw); + + color += 0.05137766 * tex2D (_MainTex, i.uv45.xy); + color += 0.05137766 * tex2D (_MainTex, i.uv45.zw); + + color += 0.009824769 * tex2D (_MainTex, i.uv67.xy); + color += 0.009824769 * tex2D (_MainTex, i.uv67.zw); + + return color * _Tint * _Intensity + Upsample(i.uv); + } + + + ENDCG + + SubShader + { + Pass // #0 Simple Downscaling + { + ZTest Always Cull Off ZWrite Off + Fog { Mode off } + + CGPROGRAM + + #pragma vertex vert_img + #pragma fragment frag + #pragma fragmentoption ARB_precision_hint_fastest + #include "UnityCG.cginc" + + + fixed4 frag(v2f i):COLOR + { + float2 UV[4]; + + UV[0] = i.uv + float2(-1.0 * _OffsetInfos.x, -1.0 * _OffsetInfos.y); + UV[1] = i.uv + float2( 1.0 * _OffsetInfos.x, -1.0 * _OffsetInfos.y); + UV[2] = i.uv + float2(-1.0 * _OffsetInfos.x, 1.0 * _OffsetInfos.y); + UV[3] = i.uv + float2( 1.0 * _OffsetInfos.x, 1.0 * _OffsetInfos.y); + + + fixed4 Sample[4]; + + for(int j = 0; j < 4; ++j) + { + Sample[j] = tex2D(_MainTex, UV[j]); + } + + return (Sample[0] + Sample[1] + Sample[2] + Sample[3]) * 1.0/4; + } + + ENDCG + } + + Pass // #1 Complex Downscaling + { + ZTest Always Cull Off ZWrite Off + Fog { Mode off } + + CGPROGRAM + + #pragma vertex vert_img + #pragma fragment frag + #pragma fragmentoption ARB_precision_hint_fastest + #include "UnityCG.cginc" + + fixed4 frag(v2f i):COLOR + { + + float2 UV[9]; + + UV[0] = i.uv; + + UV[1] = i.uv + float2( -2.0 * _OffsetInfos.x, -2.0 * _OffsetInfos.y); + UV[2] = i.uv + float2( 0.0 * _OffsetInfos.x, -2.0 * _OffsetInfos.y); + UV[3] = i.uv + float2( 2.0 * _OffsetInfos.x, -2.0 * _OffsetInfos.y); + UV[4] = i.uv + float2( -2.0 * _OffsetInfos.x, 2.0 * _OffsetInfos.y); + UV[5] = i.uv + float2( 0.0 * _OffsetInfos.x, 2.0 * _OffsetInfos.y); + UV[6] = i.uv + float2( 2.0 * _OffsetInfos.x, 2.0 * _OffsetInfos.y); + UV[7] = i.uv + float2( -2.0 * _OffsetInfos.x, 0.0 * _OffsetInfos.y); + UV[8] = i.uv + float2( 2.0 * _OffsetInfos.x, 0.0 * _OffsetInfos.y); + + + + fixed4 Sample[9]; + + for(int j = 0; j < 9; ++j) + { + Sample[j] = tex2D(_MainTex, UV[j]); + } + + half4 sum = half4(0,0,0,0); + for(int j = 0; j < 9; ++j) + { + sum += Sample[j]; + } + + return sum* 1.0/9; + } + + ENDCG + } + + Pass // #2 Gaussian Sampling Very High + { + CGPROGRAM + + #pragma fragmentoption ARB_precision_hint_fastest + #pragma exclude_renderers flash + #pragma vertex vert_img + #pragma fragment fragGaussBlurVeryHigh + + ENDCG + } + + Pass // #3 Gaussian Sampling Medium + { + CGPROGRAM + + #pragma fragmentoption ARB_precision_hint_fastest + #pragma exclude_renderers flash + #pragma vertex vert_img + #pragma fragment fragGaussBlurMedium + + ENDCG + } + + Pass // #4 Gaussian Sampling Very Low + { + CGPROGRAM + + #pragma fragmentoption ARB_precision_hint_fastest + #pragma exclude_renderers flash + #pragma vertex vertLow + #pragma fragment fragGaussBlurVeryLow + + ENDCG + } + + + Pass // #5 Filmic curve sampling + { + ZTest Always Cull Off ZWrite Off + Fog { Mode off } + + CGPROGRAM + + #pragma vertex vert_img + #pragma fragment frag + #pragma fragmentoption ARB_precision_hint_fastest + #include "UnityCG.cginc" + + // Curve mapping + half4 _Toe; + half4 _Shoulder; + half _K; + half _Crossover; + half _MaxValue; + half _CurveExposure; + float Map(half x) + { + float4 data; + float endAdd; + + if (x > _Crossover) + { + data = _Shoulder; + endAdd = _K; + } + else + { + data = _Toe; + endAdd = 0; + } + + + float2 numDenum = data.xy * x + data.zw; + return numDenum.x / numDenum.y + endAdd; + } + + + fixed4 frag(v2f i):COLOR + { + float2 UV[4]; + + UV[0] = i.uv + float2(-1.0 * _OffsetInfos.x, -1.0 * _OffsetInfos.y); + UV[1] = i.uv + float2( 1.0 * _OffsetInfos.x, -1.0 * _OffsetInfos.y); + UV[2] = i.uv + float2(-1.0 * _OffsetInfos.x, 1.0 * _OffsetInfos.y); + UV[3] = i.uv + float2( 1.0 * _OffsetInfos.x, 1.0 * _OffsetInfos.y); + + fixed4 Sample[4]; + + for(int j = 0; j < 4; ++j) + { + Sample[j] = tex2D(_MainTex, UV[j]); + } + + half4 color = (Sample[0] + Sample[1] + Sample[2] + Sample[3]) * 1.0/4; + + half intensity = ComputeLuma(color); + + + + half bloomIntensity = intensity/max(1.0+intensity*_CurveExposure,0.01); + + bloomIntensity = Map(bloomIntensity) * _MaxValue; + + return clamp(color * bloomIntensity/intensity,0,65000); + } + + ENDCG + } + + Pass // #6 Low Gaussian Filmic Curve + { + ZTest Always Cull Off ZWrite Off + Fog { Mode off } + + CGPROGRAM + + #pragma vertex vert_img + #pragma fragment frag + #pragma fragmentoption ARB_precision_hint_fastest + #include "UnityCG.cginc" + + // Curve mapping + half4 _Toe; + half4 _Shoulder; + half _K; + half _Crossover; + float Map(half x) + { + float4 data; + float endAdd; + + if (x > _Crossover) + { + data = _Shoulder; + endAdd = _K; + } + else + { + data = _Toe; + endAdd = 0; + } + + + float2 numDenum = data.xy * x + data.zw; + return numDenum.x / numDenum.y + endAdd; + } + + fixed4 frag(v2f i):COLOR + { + half4 color = half4 (0,0,0,0); + + float Scale = 9; + + float2 gUV = i.uv; + float Offset = 0; + + color += 0.4005 * tex2D (_MainTex, gUV); + color += 0.3294 * tex2D (_MainTex, gUV + _OffsetInfos.xy * 1.0); + color += 0.3294 * tex2D (_MainTex, gUV - _OffsetInfos.xy * 1.0); + color += 0.1833 * tex2D (_MainTex, gUV + _OffsetInfos.xy * 2.0); + color += 0.1833 * tex2D (_MainTex, gUV - _OffsetInfos.xy * 2.0); + color += 0.0691 * tex2D (_MainTex, gUV + _OffsetInfos.xy * 3.0); + color += 0.0691 * tex2D (_MainTex, gUV - _OffsetInfos.xy * 3.0); + color += 0.0175 * tex2D (_MainTex, gUV + _OffsetInfos.xy * 4.0); + color += 0.0175 * tex2D (_MainTex, gUV - _OffsetInfos.xy * 4.0); + + + + + half intensity = dot(color, half3(0.3,0.3,0.3)); + half bloomIntensity = Map(intensity); + + return color * bloomIntensity/intensity; + } + + ENDCG + } + + Pass // #7 Simple Blur + { + ZTest Always Cull Off ZWrite Off + Fog { Mode off } + + CGPROGRAM + + #pragma vertex vert_img + #pragma fragment frag + #pragma fragmentoption ARB_precision_hint_fastest + #include "UnityCG.cginc" + + + fixed4 frag(v2f i):COLOR + { + + + float2 UV[3]; + + UV[0] = i.uv; + UV[1] = i.uv + 1.5*_OffsetInfos; + UV[2] = i.uv - 1.5*_OffsetInfos; + //UV[2] = i.uv + 2*_OffsetInfos; + //UV[3] = i.uv - 2*_OffsetInfos; + + + fixed4 Sample[3]; + + for(int j = 0; j < 3; ++j) + { + Sample[j] = tex2D(_MainTex, UV[j]); + } + + return (Sample[0] + Sample[1] + Sample[2]) * 1.0/3; + } + + ENDCG + } + + Pass // #8 Gaussian Sampling Small + { + CGPROGRAM + + #pragma fragmentoption ARB_precision_hint_fastest + #pragma exclude_renderers flash + #pragma vertex vert_img + #pragma fragment fragGaussBlurLow + + ENDCG + } + + Pass // #9 Gaussian Sampling High + { + CGPROGRAM + + #pragma fragmentoption ARB_precision_hint_fastest + #pragma exclude_renderers flash + #pragma vertex vert_img + #pragma fragment fragGaussBlurHigh + + ENDCG + } + + Pass // #10 Gaussian Sampling Higher + { + CGPROGRAM + + #pragma fragmentoption ARB_precision_hint_fastest + #pragma exclude_renderers flash + #pragma vertex vert_img + #pragma fragment fragGaussBlurHigher + + ENDCG + } + + Pass // #11 Temporal Stable Downsampling + { + ZTest Always Cull Off ZWrite Off + Fog { Mode off } + + CGPROGRAM + + #pragma vertex vert_img + #pragma fragment frag + #pragma fragmentoption ARB_precision_hint_fastest + #include "UnityCG.cginc" + float2 _MainTex_TexelSize; + + fixed4 frag(v2f i):COLOR + { + float4 offsets = _MainTex_TexelSize.xyxy * float4(-1.0, -1.0, +1.0, +1.0); + half3 c0 = tex2D(_MainTex, i.uv + offsets.xy); + half3 c1 = tex2D(_MainTex, i.uv + offsets.zy); + half3 c2 = tex2D(_MainTex, i.uv + offsets.xw); + half3 c3 = tex2D(_MainTex, i.uv + offsets.zw); + half w0 = 1.0 / (ComputeLuma(c0) + 1.0); + half w1 = 1.0 / (ComputeLuma(c1) + 1.0); + half w2 = 1.0 / (ComputeLuma(c2) + 1.0); + half w3 = 1.0 / (ComputeLuma(c3) + 1.0); + half div = 1.0 / max(w0 + w1 + w2 + w3, 0.01); + float3 color = (c0 * w0 + c1 * w1 + c2 * w2 + c3 * w3) * div; + + return float4(clamp(color,0,65000), 1); + + //half intensity = dot(color, half3(0.3,0.3,0.3)); + + //half bloomIntensity = intensity/max(1.0+intensity*_CurveExposure,0.01); + + //return float4(clamp(color * bloomIntensity/intensity,0,65000), 1); + } + + ENDCG + } + + + Pass // #12 Temporal Stable Downsampling with filmic curve + { + ZTest Always Cull Off ZWrite Off + Fog { Mode off } + + CGPROGRAM + + #pragma vertex vert_img + #pragma fragment frag + #pragma fragmentoption ARB_precision_hint_fastest + #include "UnityCG.cginc" + float2 _MainTex_TexelSize; + + // Curve mapping + half4 _Toe; + half4 _Shoulder; + half _K; + half _Crossover; + half _MaxValue; + half _CurveExposure; + float Map(half x) + { + float4 data; + float endAdd; + + if (x > _Crossover) + { + data = _Shoulder; + endAdd = _K; + } + else + { + data = _Toe; + endAdd = 0; + } + + + float2 numDenum = data.xy * x + data.zw; + return numDenum.x / numDenum.y + endAdd; + } + + fixed4 frag(v2f i):COLOR + { + float4 offsets = _MainTex_TexelSize.xyxy * float4(-1.0, -1.0, +1.0, +1.0); + half3 c0 = tex2D(_MainTex, i.uv + offsets.xy); + half3 c1 = tex2D(_MainTex, i.uv + offsets.zy); + half3 c2 = tex2D(_MainTex, i.uv + offsets.xw); + half3 c3 = tex2D(_MainTex, i.uv + offsets.zw); + half w0 = 1.0 / (ComputeLuma(c0) + 1.0); + half w1 = 1.0 / (ComputeLuma(c1) + 1.0); + half w2 = 1.0 / (ComputeLuma(c2) + 1.0); + half w3 = 1.0 / (ComputeLuma(c3) + 1.0); + half div = 1.0 / max(w0 + w1 + w2 + w3, 0.01); + float3 color = (c0 * w0 + c1 * w1 + c2 * w2 + c3 * w3) * div; + + half intensity = ComputeLuma(color); + + half bloomIntensity = intensity/max(1.0+intensity*_CurveExposure,0.01); + bloomIntensity = Map(bloomIntensity) * _MaxValue; + + return float4(clamp(color * bloomIntensity/intensity,0,65000), 1); + } + + ENDCG + } + + } + + FallBack off +} diff --git a/Assets/Cinematic Effects/BloomBeta/Resources/UltimateSampling.shader.meta b/Assets/Cinematic Effects/BloomBeta/Resources/UltimateSampling.shader.meta new file mode 100644 index 0000000..c527d0f --- /dev/null +++ b/Assets/Cinematic Effects/BloomBeta/Resources/UltimateSampling.shader.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: aae4bb3d598e50d4bada0867c1df4eb4 +ShaderImporter: + defaultTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/BloomBeta/Scripts.meta b/Assets/Cinematic Effects/BloomBeta/Scripts.meta new file mode 100644 index 0000000..14d4900 --- /dev/null +++ b/Assets/Cinematic Effects/BloomBeta/Scripts.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 8d98caaa93f108b4a8be214f58dfe23f +folderAsset: yes +timeCreated: 1443580217 +licenseType: Store +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/BloomBeta/Scripts/BokehRenderer.cs b/Assets/Cinematic Effects/BloomBeta/Scripts/BokehRenderer.cs new file mode 100644 index 0000000..fe10124 --- /dev/null +++ b/Assets/Cinematic Effects/BloomBeta/Scripts/BokehRenderer.cs @@ -0,0 +1,191 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using UnityEngine; + + +class BokehRenderer +{ + Texture2D m_CurrentTexture; + //Mesh[] m_FlareMeshes = null; + Material m_FlareMaterial; + + int m_CurrentWidth; + int m_CurrentHeight; + float m_CurrentRelativeScaleX; + float m_CurrentRelativeScaleY; + + public BokehRenderer() + { + + } + + public void RebuildMeshIfNeeded(int width, int height, float spriteRelativeScaleX, float spriteRelativeScaleY, ref Mesh[] meshes) + { + if (m_CurrentWidth == width && m_CurrentHeight == height && m_CurrentRelativeScaleX == spriteRelativeScaleX && m_CurrentRelativeScaleY == spriteRelativeScaleY && meshes != null) + return; + + if (meshes != null) + foreach (Mesh m in meshes) + { + GameObject.DestroyImmediate(m, true); + } + meshes = null; + + BuildMeshes(width, height, spriteRelativeScaleX, spriteRelativeScaleY, ref meshes); + + } + + public void BuildMeshes(int width, int height, float spriteRelativeScaleX, float spriteRelativeScaleY, ref Mesh[] meshes) + { + int maxQuads = 65000 / 6; + int totalQuads = width * height; + int meshCount = Mathf.CeilToInt((1.0f * totalQuads) / (1.0f * maxQuads)); + meshes = new Mesh[meshCount]; + int currentQuads = totalQuads; + + + m_CurrentWidth = width; + m_CurrentHeight = height; + m_CurrentRelativeScaleX = spriteRelativeScaleX; + m_CurrentRelativeScaleY = spriteRelativeScaleY; + int currentPixel = 0; + + for (int m = 0; m < meshCount; ++m) + { + Mesh currentMesh = new Mesh(); + currentMesh.hideFlags = HideFlags.HideAndDontSave; + + int nbQuads = currentQuads; + if (currentQuads > maxQuads) + nbQuads = maxQuads; + currentQuads -= nbQuads; + + Vector3[] vertices = new Vector3[nbQuads * 4]; + int[] triangles = new int[nbQuads * 6]; + Vector2[] uv0 = new Vector2[nbQuads * 4]; + Vector2[] uv1 = new Vector2[nbQuads * 4]; + Vector3[] normals = new Vector3[nbQuads * 4]; + Color[] colors = new Color[nbQuads * 4]; + + float spriteWidth = m_CurrentRelativeScaleX * width; + float spriteHeigth = m_CurrentRelativeScaleY * height; + + + for (int i = 0; i < nbQuads; ++i) + { + int x = currentPixel % width; + int y = (currentPixel - x) / width; + SetupSprite(i, x, y, vertices, triangles, uv0, uv1, normals, colors, new Vector2((float)x / (float)width, 1.0f - ((float)y / (float)height)), spriteWidth * 0.5f, spriteHeigth * 0.5f); + currentPixel++; + } + + currentMesh.vertices = vertices; + currentMesh.triangles = triangles; + currentMesh.colors = colors; + currentMesh.uv = uv0; + currentMesh.uv2 = uv1; + currentMesh.normals = normals; + currentMesh.RecalculateBounds(); + currentMesh.UploadMeshData(true); + meshes[m] = currentMesh; + } + } + + public void Clear(ref Mesh[] meshes) + { + if (meshes != null) + foreach (Mesh m in meshes) + { + GameObject.DestroyImmediate(m, true); + } + meshes = null; + } + + public void SetTexture(Texture2D texture) + { + m_CurrentTexture = texture; + m_FlareMaterial.SetTexture("_MainTex", m_CurrentTexture); + } + + public void SetMaterial(Material flareMaterial) + { + m_FlareMaterial = flareMaterial; + } + + public void RenderFlare(RenderTexture brightPixels, RenderTexture destination, float intensity, ref Mesh[] meshes) + { + + RenderTexture lastActive = RenderTexture.active; + + RenderTexture.active = destination; + GL.Clear(true, true, Color.black); + + Matrix4x4 proj = Matrix4x4.Ortho(0, m_CurrentWidth, 0, m_CurrentHeight, -1.0f, 1.0f); + + m_FlareMaterial.SetMatrix("_FlareProj", proj); + m_FlareMaterial.SetTexture("_BrightTexture", brightPixels); + m_FlareMaterial.SetFloat("_Intensity", intensity); + + if (m_FlareMaterial.SetPass(0)) + { + //Debug.Log("MeshCount=" + m_FlareMeshes.Length); + + for (int i = 0; i < meshes.Length; ++i ) + Graphics.DrawMeshNow(meshes[i], Matrix4x4.identity); + } + else + { + Debug.LogError("Can't render flare mesh"); + } + + RenderTexture.active = lastActive; + + } + + public void SetupSprite(int idx, int x, int y, Vector3[] vertices, int[] triangles, Vector2[] uv0, Vector2[] uv1, Vector3[] normals, Color[] colors, Vector2 targetPixelUV, float halfWidth, float halfHeight) + { + int vIdx = idx * 4; + int tIdx = idx * 6; + + triangles[tIdx + 0] = vIdx + 0; + triangles[tIdx + 1] = vIdx + 2; + triangles[tIdx + 2] = vIdx + 1; + + triangles[tIdx + 3] = vIdx + 2; + triangles[tIdx + 4] = vIdx + 3; + triangles[tIdx + 5] = vIdx + 1; + + vertices[vIdx + 0] = new Vector3((-halfWidth + x), (-halfHeight + y), 0); + vertices[vIdx + 1] = new Vector3((halfWidth + x), (-halfHeight + y), 0); + vertices[vIdx + 2] = new Vector3((-halfWidth + x), (halfHeight + y), 0); + vertices[vIdx + 3] = new Vector3((halfWidth + x), (halfHeight + y), 0); + + Vector2 p = targetPixelUV; + + colors[vIdx + 0] = new Color((-halfWidth / m_CurrentWidth + p.x), (-halfHeight*-1/ m_CurrentHeight + p.y), 0, 0); + colors[vIdx + 1] = new Color((halfWidth / m_CurrentWidth + p.x), (-halfHeight * -1 / m_CurrentHeight + p.y), 0, 0); + colors[vIdx + 2] = new Color((-halfWidth / m_CurrentWidth + p.x), (halfHeight * -1 / m_CurrentHeight + p.y), 0, 0); + colors[vIdx + 3] = new Color((halfWidth / m_CurrentWidth + p.x), (halfHeight * -1 / m_CurrentHeight + p.y), 0, 0); + + normals[vIdx + 0] = -Vector3.forward; + normals[vIdx + 1] = -Vector3.forward; + normals[vIdx + 2] = -Vector3.forward; + normals[vIdx + 3] = -Vector3.forward; + + uv0[vIdx + 0] = new Vector2(0, 0); + uv0[vIdx + 1] = new Vector2(1.0f, 0); + uv0[vIdx + 2] = new Vector2(0, 1.0f); + uv0[vIdx + 3] = new Vector2(1.0f, 1.0f); + + uv1[vIdx + 0] = targetPixelUV; + uv1[vIdx + 1] = targetPixelUV; + uv1[vIdx + 2] = targetPixelUV; + uv1[vIdx + 3] = targetPixelUV; + } + + + +} + diff --git a/Assets/Cinematic Effects/BloomBeta/Scripts/BokehRenderer.cs.meta b/Assets/Cinematic Effects/BloomBeta/Scripts/BokehRenderer.cs.meta new file mode 100644 index 0000000..27b1699 --- /dev/null +++ b/Assets/Cinematic Effects/BloomBeta/Scripts/BokehRenderer.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: f26e82e850c24c444bb8306feb47738d +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/BloomBeta/Scripts/DeluxeFilmicCurve.cs b/Assets/Cinematic Effects/BloomBeta/Scripts/DeluxeFilmicCurve.cs new file mode 100644 index 0000000..2fd397c --- /dev/null +++ b/Assets/Cinematic Effects/BloomBeta/Scripts/DeluxeFilmicCurve.cs @@ -0,0 +1,241 @@ +using UnityEngine; +using System.Collections; +using System; +using UnityEditor; + +#if UNITY_EDITOR +using UnityEditor; +#endif + +[Serializable] +public class DeluxeFilmicCurve +{ + [SerializeField] + public float m_BlackPoint = 0.0f; + + [SerializeField] + public float m_WhitePoint = 1.0f; + + [SerializeField] + public float m_CrossOverPoint = 0.3f; + + [SerializeField] + public float m_ToeStrength = 0.98f; + + [SerializeField] + public float m_ShoulderStrength = 0.0f; + + [SerializeField] + public float m_Highlights = 0.5f; + + public float m_k; + public Vector4 m_ToeCoef; + public Vector4 m_ShoulderCoef; + + public float GetExposure() + { + float highlights = m_Highlights; + float exposure = 2.0f + (1.0f - highlights) * 20.0f; + return (exposure * Mathf.Exp(-2.0f)); + } + + public float ComputeK(float t, float c, float b, float s, float w) + { + float num = (1 - t) * (c - b); + float denom = (1 - s) * (w - c) + (1 - t) * (c - b); + + return num / denom; + } + + public float Toe(float x, float t, float c, float b, float s, float w, float k) + { + float xnum = m_ToeCoef.x * x; + float xdenom = m_ToeCoef.y * x; + + return (xnum + m_ToeCoef.z) / (xdenom + m_ToeCoef.w); + + /*float num = k * (1 - t) * (x - b); + float denom = c - (1 - t) * b - t * x; + + return num / denom;*/ + } + + public float Shoulder(float x, float t, float c, float b, float s, float w, float k) + { + float xnum = m_ShoulderCoef.x * x; + float xdenom = m_ShoulderCoef.y * x; + + return (xnum + m_ShoulderCoef.z) / (xdenom + m_ShoulderCoef.w) + k; + + /*float num = (1 - k) * (x - c); + float denom = s*x + (1 - s) * w - c; + + return num / denom + k;*/ + } + + public float Graph(float x, float t, float c, float b, float s, float w, float k) + { + if (x <= m_CrossOverPoint) + return Toe(x, t, c, b, s, w, k); + + return Shoulder(x, t, c, b, s, w, k); + } + + public void StoreK() + { + m_k = ComputeK(m_ToeStrength, m_CrossOverPoint, m_BlackPoint, m_ShoulderStrength, m_WhitePoint); + } + + public void ComputeShaderCoefficients(float t, float c, float b, float s, float w, float k) + { + { + float xNumMul = k * (1 - t); + float numAdd = k * (1 - t) * -b; + float xDenomMul = -t; + float denomAdd = c - (1 - t) * b; + m_ToeCoef = new Vector4(xNumMul, xDenomMul, numAdd, denomAdd); + } + + { + float xNumMul = (1 - k); + float numAdd = (1 - k) * -c; + float xDenomMul = s; + float denomAdd = (1 - s) * w - c; + m_ShoulderCoef = new Vector4(xNumMul, xDenomMul, numAdd, denomAdd); + } + } + + public void UpdateCoefficients() + { + StoreK(); + ComputeShaderCoefficients(m_ToeStrength, m_CrossOverPoint, m_BlackPoint, m_ShoulderStrength, m_WhitePoint, m_k); + } + + + + + Vector3[] m_CurvePoints; + + void DrawCurve() + { + //Rect rr = GUILayoutUtility.GetRect(Mathf.Min(r.width, 60), 60); + //if (m_CurvePoints != null) + { + const int h = 100; + const int h1 = h - 1; + Rect rect; + + EditorGUILayout.BeginHorizontal(); + GUILayout.FlexibleSpace(); + rect = GUILayoutUtility.GetRect(Mathf.Max(EditorGUIUtility.currentViewWidth - 50.0f, 10.0f), h); + GUILayout.FlexibleSpace(); + EditorGUILayout.EndHorizontal(); + GUI.Box(rect, GUIContent.none); + + int nbPoint = 40; + int w = Mathf.FloorToInt(rect.width); + + Vector3[] points = new Vector3[nbPoint]; + + for (int i = 0; i < nbPoint; i++) + { + float norm = (float)i / (float)nbPoint; + float value = Graph(norm * m_WhitePoint, m_ToeStrength, m_CrossOverPoint, m_BlackPoint, m_ShoulderStrength, m_WhitePoint, m_k); + value = Mathf.Clamp01(value); + points[i] = new Vector3(rect.x + i * (float)w / (float)(nbPoint - 1), rect.y + (h - value * h1), 0f); + } + + + Handles.color = Color.green; + Handles.DrawAAPolyLine(2f, points); + } + //EditorGUI.CurveField(rr, m_Curve); + } + + public void OnGUI() + { + //SetupCurve(); + + float denom = m_WhitePoint - m_BlackPoint; + + float co = (m_CrossOverPoint - m_BlackPoint) / denom; + if (Mathf.Abs(denom) < 0.001f) + co = 0.5f; + + EditorGUILayout.LabelField("Curve Parameters", EditorStyles.boldLabel); + m_WhitePoint = 1.0f; + m_BlackPoint = 0.0f; + co = DoSlider("Middle", co, 0.0f, 1.0f); + m_ToeStrength = -1.0f * DoSlider("Dark", -1.0f * m_ToeStrength, -0.99f, 0.99f); + m_ShoulderStrength = DoSlider("Bright", m_ShoulderStrength, -0.99f, 0.99f); + m_Highlights = DoSlider("Highlights", m_Highlights, 0.0f, 1.0f); + + m_CrossOverPoint = co * (m_WhitePoint - m_BlackPoint) + m_BlackPoint; + UpdateCoefficients(); + + EditorGUILayout.BeginVertical(GUILayout.MinHeight(60)); + // Curve drawing + DrawCurve(); + EditorGUILayout.EndVertical(); + } + + AnimationCurve m_Curve; + + private static float CalculateLinearTangent(AnimationCurve curve, int index, int toIndex) + { + return (float)(((double)curve[index].value - (double)curve[toIndex].value) / ((double)curve[index].time - (double)curve[toIndex].time)); + } + + void SetupCurve() + { + m_Curve = new AnimationCurve(); + + DeluxeFilmicCurve dt = this; + + float min = dt.m_BlackPoint; + float max = dt.m_WhitePoint; + + int nbFrame = 40; + float step = (max - min) / nbFrame; + + m_CurvePoints = new Vector3[nbFrame + 1]; + + float curr = min; + float k = dt.ComputeK(dt.m_ToeStrength, dt.m_CrossOverPoint, dt.m_BlackPoint, dt.m_ShoulderStrength, dt.m_WhitePoint); + + dt.StoreK(); + dt.ComputeShaderCoefficients(dt.m_ToeStrength, dt.m_CrossOverPoint, dt.m_BlackPoint, dt.m_ShoulderStrength, dt.m_WhitePoint, k); + + for (int i = 0; i < nbFrame + 1; ++i) + { + float value = dt.Graph(curr, dt.m_ToeStrength, dt.m_CrossOverPoint, dt.m_BlackPoint, dt.m_ShoulderStrength, dt.m_WhitePoint, k); + + m_CurvePoints[i] = new Vector3(curr, value); + + m_Curve.AddKey(new Keyframe(curr, value)); + + curr += step; + } + + for (int i = 0; i < m_Curve.keys.Length - 1; ++i) + { + float tangent = CalculateLinearTangent(m_Curve, i, i + 1); + m_Curve.keys[i].inTangent = tangent; + m_Curve.keys[i].outTangent = tangent; + + m_Curve.SmoothTangents(i, 0.0f); + } + } + + float DoSlider(string label, float value, float min, float max) + { + float v = value; + EditorGUILayout.BeginHorizontal(); + v = Mathf.Clamp(EditorGUILayout.FloatField(label, v), min, max); + v = GUILayout.HorizontalSlider(v, min, max); + EditorGUILayout.EndHorizontal(); + + return v; + } + +} diff --git a/Assets/Cinematic Effects/BloomBeta/Scripts/DeluxeFilmicCurve.cs.meta b/Assets/Cinematic Effects/BloomBeta/Scripts/DeluxeFilmicCurve.cs.meta new file mode 100644 index 0000000..50d545d --- /dev/null +++ b/Assets/Cinematic Effects/BloomBeta/Scripts/DeluxeFilmicCurve.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 4b47c958d5706f24d8fc004492f16384 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/BloomBeta/Scripts/UBHelper.cs b/Assets/Cinematic Effects/BloomBeta/Scripts/UBHelper.cs new file mode 100644 index 0000000..797b6d7 --- /dev/null +++ b/Assets/Cinematic Effects/BloomBeta/Scripts/UBHelper.cs @@ -0,0 +1,84 @@ +using UnityEngine; +using System.Collections; + +public class UBHelper : MonoBehaviour +{ + + static UBHelper() + { + s_Styles = new Styles(); + } + + public static bool GroupHeader(string text, bool isExpanded) + { + Rect rect = GUILayoutUtility.GetRect(16f, 22f, s_Styles.header); + + s_Styles.Backup(); + s_Styles.Apply(); + + if (Event.current.type == EventType.Repaint) + s_Styles.header.Draw(rect, text, isExpanded, isExpanded, isExpanded, isExpanded); + + Event e = Event.current; + if (e.type == EventType.MouseDown) + { + if (rect.Contains(e.mousePosition)) + { + isExpanded = !isExpanded; + e.Use(); + } + } + + s_Styles.Revert(); + return isExpanded; + } + + private static Styles s_Styles; + private class Styles + { + public GUIStyle header = "ShurikenModuleTitle"; + public GUIStyle headerArrow = "AC RightArrow"; + + internal Styles() + { + header.font = (new GUIStyle("Label")).font; + } + + RectOffset m_Border; + float m_FixedHeight; + Vector2 m_ContentOffset; + TextAnchor m_TextAlign; + FontStyle m_TextStyle; + int m_FontSize; + + public void Backup() + { + m_Border = s_Styles.header.border; + m_FixedHeight = s_Styles.header.fixedHeight; + m_ContentOffset = s_Styles.header.contentOffset; + m_TextAlign = s_Styles.header.alignment; + m_TextStyle = s_Styles.header.fontStyle; + m_FontSize = s_Styles.header.fontSize; + } + + public void Apply() + { + s_Styles.header.border = new RectOffset(7, 7, 4, 4); + s_Styles.header.fixedHeight = 22; + s_Styles.header.contentOffset = new Vector2(20f, -2f); + s_Styles.header.alignment = TextAnchor.MiddleLeft; + s_Styles.header.fontStyle = FontStyle.Bold; + s_Styles.header.fontSize = 12; + } + + public void Revert() + { + s_Styles.header.border = m_Border; + s_Styles.header.fixedHeight = m_FixedHeight; + s_Styles.header.contentOffset = m_ContentOffset; + s_Styles.header.alignment = m_TextAlign; + s_Styles.header.fontStyle = m_TextStyle; + s_Styles.header.fontSize = m_FontSize; + } + } +} diff --git a/Assets/Cinematic Effects/BloomBeta/Scripts/UBHelper.cs.meta b/Assets/Cinematic Effects/BloomBeta/Scripts/UBHelper.cs.meta new file mode 100644 index 0000000..493d597 --- /dev/null +++ b/Assets/Cinematic Effects/BloomBeta/Scripts/UBHelper.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 68539e60785f1d44c8848e40b66f760f +timeCreated: 1456307053 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/BloomBeta/Scripts/UltimateBloom.cs b/Assets/Cinematic Effects/BloomBeta/Scripts/UltimateBloom.cs new file mode 100644 index 0000000..4ec9961 --- /dev/null +++ b/Assets/Cinematic Effects/BloomBeta/Scripts/UltimateBloom.cs @@ -0,0 +1,1568 @@ +using UnityEngine; +using System.Collections; +using System; +#if UNITY_EDITOR +using UnityEditor; +using System.IO; +#endif + +[ExecuteInEditMode] +[RequireComponent(typeof(Camera))] +public class UltimateBloom : MonoBehaviour +{ + + public enum BloomQualityPreset + { + Optimized, + Standard, + HighVisuals, + Custom + } + + public enum BloomSamplingQuality + { + VerySmallKernel, // 9 + SmallKernel, // 13 + MediumKernel, // 17 + LargeKernel, // 23 + LargerKernel, // 27 + VeryLargeKernel // 31 + } + + public enum BloomScreenBlendMode + { + Screen = 0, + Add = 1, + } + + public enum HDRBloomMode + { + Auto = 0, + On = 1, + Off = 2, + } + + public enum BlurSampleCount + { + Nine, + Seventeen, + Thirteen, + TwentyThree, + TwentySeven, + ThrirtyOne, + NineCurve, + FourSimple + } + + public enum FlareRendering + { + Sharp, + Blurred, + MoreBlurred + } + + public enum SimpleSampleCount + { + Four, + Nine, + FourCurve, + ThirteenTemporal, + ThirteenTemporalCurve + } + + public enum FlareType + { + Single, + Double + } + + public enum BloomIntensityManagement + { + FilmicCurve, + Threshold + } + + private enum FlareStripeType + { + Anamorphic, + Star, + DiagonalUpright, + DiagonalUpleft + } + + public enum AnamorphicDirection + { + Horizontal, + Vertical + } + + public enum BokehFlareQuality + { + Low, + Medium, + High, + VeryHigh + } + + public enum BlendMode + { + ADD, + SCREEN + } + + public enum SamplingMode + { + Fixed, + HeightRelative + } + + public enum FlareBlurQuality + { + Fast, + Normal, + High + } + + public enum FlarePresets + { + ChoosePreset, + GhostFast, + Ghost1, + Ghost2, + Ghost3, + Bokeh1, + Bokeh2, + Bokeh3 + } + + + + public float m_SamplingMinHeight = 400.0f; + public float[] m_ResSamplingPixelCount = new float[6]; + + public SamplingMode m_SamplingMode = SamplingMode.Fixed; + + public BlendMode m_BlendMode = BlendMode.ADD; + public float m_ScreenMaxIntensity; + + public BloomQualityPreset m_QualityPreset; + + public HDRBloomMode m_HDR = HDRBloomMode.Auto; + + public BloomScreenBlendMode m_ScreenBlendMode = BloomScreenBlendMode.Add; + + public float m_BloomIntensity = 1.0f; + + public float m_BloomThreshhold = 0.5f; + public Color m_BloomThreshholdColor = Color.white; + public int m_DownscaleCount = 5; + public BloomIntensityManagement m_IntensityManagement = BloomIntensityManagement.FilmicCurve; + public float[] m_BloomIntensities; + public Color[] m_BloomColors; + public bool[] m_BloomUsages; + + [SerializeField] + public DeluxeFilmicCurve m_BloomCurve = new DeluxeFilmicCurve(); + + private int m_LastDownscaleCount = 5; + + public bool m_UseLensFlare = false; + public float m_FlareTreshold = 0.8f; + public float m_FlareIntensity = 0.25f; + + public Color m_FlareTint0 = new Color(137 / 255.0f, 82 / 255.0f, 0 / 255.0f); + public Color m_FlareTint1 = new Color(0 / 255.0f, 63 / 255.0f, 126 / 255.0f); + public Color m_FlareTint2 = new Color(72 / 255.0f, 151 / 255.0f, 0 / 255.0f); + public Color m_FlareTint3 = new Color(114 / 255.0f, 35 / 255.0f, 0 / 255.0f); + public Color m_FlareTint4 = new Color(122 / 255.0f, 88 / 255.0f, 0 / 255.0f); + public Color m_FlareTint5 = new Color(137 / 255.0f, 71 / 255.0f, 0 / 255.0f); + public Color m_FlareTint6 = new Color(97 / 255.0f, 139 / 255.0f, 0 / 255.0f); + public Color m_FlareTint7 = new Color(40 / 255.0f, 142 / 255.0f, 0 / 255.0f); + + public float m_FlareGlobalScale = 1.0f; + public Vector4 m_FlareScales = new Vector4(1.0f, 0.6f, 0.5f, 0.4f); + public Vector4 m_FlareScalesNear = new Vector4(1.0f, 0.8f, 0.6f, 0.5f); + public Texture2D m_FlareMask; + public FlareRendering m_FlareRendering = FlareRendering.Blurred; + public FlareType m_FlareType = FlareType.Double; + public Texture2D m_FlareShape; + public FlareBlurQuality m_FlareBlurQuality = FlareBlurQuality.High; + BokehRenderer m_FlareSpriteRenderer; + Mesh[] m_BokehMeshes; + public bool m_UseBokehFlare = false; + public float m_BokehScale = 0.4f; + //public bool m_HighQualityBokehFlare = true; + public BokehFlareQuality m_BokehFlareQuality = BokehFlareQuality.Medium; + + public bool m_UseAnamorphicFlare = false; + public float m_AnamorphicFlareTreshold = 0.8f; + public float m_AnamorphicFlareIntensity = 1.0f; + public int m_AnamorphicDownscaleCount = 3; + public int m_AnamorphicBlurPass = 2; + private int m_LastAnamorphicDownscaleCount; + private RenderTexture[] m_AnamorphicUpscales; + public float[] m_AnamorphicBloomIntensities; + public Color[] m_AnamorphicBloomColors; + public bool[] m_AnamorphicBloomUsages; + public bool m_AnamorphicSmallVerticalBlur = true; + public AnamorphicDirection m_AnamorphicDirection = AnamorphicDirection.Horizontal; + public float m_AnamorphicScale = 3.0f; + + + public bool m_UseStarFlare = false; + public float m_StarFlareTreshol = 0.8f; + public float m_StarFlareIntensity = 1.0f; + public float m_StarScale = 2.0f; + public int m_StarDownscaleCount = 3; + public int m_StarBlurPass = 2; + private int m_LastStarDownscaleCount; + private RenderTexture[] m_StarUpscales; + public float[] m_StarBloomIntensities; + public Color[] m_StarBloomColors; + public bool[] m_StarBloomUsages; + + public bool m_UseLensDust = false; + public float m_DustIntensity = 1.0f; + public Texture2D m_DustTexture; + public float m_DirtLightIntensity = 5.0f; + + public BloomSamplingQuality m_DownsamplingQuality; + public BloomSamplingQuality m_UpsamplingQuality; + public bool m_TemporalStableDownsampling = true; + + + // Misc + public bool m_InvertImage = false; + + + // Materials/shaders + private Material m_FlareMaterial; + private Shader m_FlareShader; + private Material m_SamplingMaterial; + private Shader m_SamplingShader; + private Material m_CombineMaterial; + private Shader m_CombineShader; + private Material m_BrightpassMaterial; + private Shader m_BrightpassShader; + private Material m_FlareMaskMaterial; + private Shader m_FlareMaskShader; + private Material m_MixerMaterial; + private Shader m_MixerShader; + + private Material m_FlareBokehMaterial; + private Shader m_FlareBokehShader; + + // Optimization + public bool m_DirectDownSample = false; + public bool m_DirectUpsample = false; + + // UI + public bool m_UiShowBloomScales = false; + public bool m_UiShowAnamorphicBloomScales = false; + public bool m_UiShowStarBloomScales = false; + public bool m_UiShowHeightSampling = false; + + + public bool m_UiShowBloomSettings = false; + public bool m_UiShowSampling = false; + public bool m_UiShowIntensity = false; + public bool m_UiShowOptimizations = false; + public bool m_UiShowLensDirt = false; + public bool m_UiShowLensFlare = false; + public bool m_UiShowAnamorphic = false; + public bool m_UiShowStar = false; + +#if UNITY_EDITOR + public bool m_UiInitialized = false; + void OnEnable() + { + if (!m_UiInitialized && !Application.isPlaying) + { + m_UiInitialized = true; + IntializeUltimateBloom(); + } + } + + public static string GetAbsoluteAssetPath(string path) + { + UltimateBloomPathLocator locator = ScriptableObject.CreateInstance(); + MonoScript script = MonoScript.FromScriptableObject(locator); + string scriptPath = AssetDatabase.GetAssetPath(script); + ScriptableObject.DestroyImmediate(locator); + return Path.GetDirectoryName(scriptPath) + "/" + path; + } + + private void IntializeUltimateBloom() + { + CreateMaterials(); + + m_BloomUsages[0] = false; + m_AnamorphicBloomUsages[0] = true; + m_AnamorphicBloomUsages[1] = true; + m_StarBloomUsages[0] = true; + m_StarBloomUsages[1] = true; + m_UpsamplingQuality = UltimateBloom.BloomSamplingQuality.SmallKernel; + + string flareMaskPath = GetAbsoluteAssetPath("Graphics/FlareMask.png"); + Texture2D flareMask = (Texture2D)AssetDatabase.LoadAssetAtPath(flareMaskPath, typeof(Texture2D)); + m_FlareMask = flareMask; + + string bokehPath = GetAbsoluteAssetPath("Graphics/Bokeh.png"); + Texture2D bokeh = (Texture2D)AssetDatabase.LoadAssetAtPath(bokehPath, typeof(Texture2D)); + m_FlareShape = bokeh; + + string dustPath = GetAbsoluteAssetPath("DirtTextureSample/Dust.tif"); + Texture2D dust = (Texture2D)AssetDatabase.LoadAssetAtPath(dustPath, typeof(Texture2D)); + m_DustTexture = dust; + + m_BloomCurve.UpdateCoefficients(); + } +#endif + + + private void DestroyMaterial(Material mat) + { + if (mat) + { + DestroyImmediate(mat); + mat = null; + } + } + + private void LoadShader(ref Material material, ref Shader shader, string shaderPath) + { + if (shader != null) + return; + shader = Shader.Find(shaderPath); + if (shader == null) + { + Debug.LogError("Shader not found: " + shaderPath); + return; + } + + + if (!shader.isSupported) + { + Debug.LogError("Shader contains error: " + shaderPath + "\n Maybe include path? Try rebuilding the shader."); + return; + } + + material = CreateMaterial(shader); + } + + public void CreateMaterials() + { + //m_FlareType = FlareType.Double; + int maxScaleCount = 8; + if (m_BloomIntensities == null || m_BloomIntensities.Length < maxScaleCount) + { + m_BloomIntensities = new float[maxScaleCount]; + for (int i = 0; i < 8; ++i) + m_BloomIntensities[i] = 1.0f; + } + if (m_BloomColors == null || m_BloomColors.Length < maxScaleCount) + { + m_BloomColors = new Color[maxScaleCount]; + for (int i = 0; i < 8; ++i) + m_BloomColors[i] = Color.white; + } + if (m_BloomUsages == null || m_BloomUsages.Length < maxScaleCount ) + { + m_BloomUsages = new bool[maxScaleCount]; + for (int i = 0; i < 8; ++i) + m_BloomUsages[i] = true; + } + + if (m_AnamorphicBloomIntensities == null || m_AnamorphicBloomIntensities.Length < maxScaleCount) + { + m_AnamorphicBloomIntensities = new float[maxScaleCount]; + for (int i = 0; i < 8; ++i) + m_AnamorphicBloomIntensities[i] = 1.0f; + } + if (m_AnamorphicBloomColors == null || m_AnamorphicBloomColors.Length < maxScaleCount) + { + m_AnamorphicBloomColors = new Color[maxScaleCount]; + for (int i = 0; i < 8; ++i) + m_AnamorphicBloomColors[i] = Color.white; + } + if (m_AnamorphicBloomUsages == null || m_AnamorphicBloomUsages.Length < maxScaleCount ) + { + m_AnamorphicBloomUsages = new bool[maxScaleCount]; + for (int i = 0; i < 8; ++i) + m_AnamorphicBloomUsages[i] = true; + } + + if (m_StarBloomIntensities == null || m_StarBloomIntensities.Length < maxScaleCount) + { + m_StarBloomIntensities = new float[maxScaleCount]; + for (int i = 0; i < 8; ++i) + m_StarBloomIntensities[i] = 1.0f; + } + if (m_StarBloomColors == null || m_StarBloomColors.Length < maxScaleCount) + { + m_StarBloomColors = new Color[maxScaleCount]; + for (int i = 0; i < 8; ++i) + m_StarBloomColors[i] = Color.white; + } + if (m_StarBloomUsages == null || m_StarBloomUsages.Length < maxScaleCount) + { + m_StarBloomUsages = new bool[maxScaleCount]; + for (int i = 0; i < 8; ++i) + m_StarBloomUsages[i] = true; + } + + if (m_FlareSpriteRenderer == null && m_FlareShape != null && m_UseBokehFlare) + { + if (m_FlareSpriteRenderer != null) + m_FlareSpriteRenderer.Clear(ref m_BokehMeshes); + + m_FlareSpriteRenderer = new BokehRenderer(); + } + + if (m_SamplingMaterial == null) + { + m_DownSamples = new RenderTexture[GetNeededDownsamples()]; + m_UpSamples = new RenderTexture[m_DownscaleCount]; + m_AnamorphicUpscales = new RenderTexture[m_AnamorphicDownscaleCount]; + m_StarUpscales = new RenderTexture[m_StarDownscaleCount]; + } + + string flareShaderPath = m_FlareType == FlareType.Single ? "Hidden/Ultimate/FlareSingle" : "Hidden/Ultimate/FlareDouble"; + LoadShader(ref m_FlareMaterial, ref m_FlareShader, flareShaderPath); + + LoadShader(ref m_SamplingMaterial, ref m_SamplingShader, "Hidden/Ultimate/Sampling"); + LoadShader(ref m_BrightpassMaterial, ref m_BrightpassShader, "Hidden/Ultimate/BrightpassMask"); + LoadShader(ref m_FlareMaskMaterial, ref m_FlareMaskShader, "Hidden/Ultimate/FlareMask"); + LoadShader(ref m_MixerMaterial, ref m_MixerShader, "Hidden/Ultimate/BloomMixer"); + LoadShader(ref m_FlareBokehMaterial, ref m_FlareBokehShader, "Hidden/Ultimate/FlareMesh"); + + bool useDustOrFlare = m_UseLensDust || m_UseLensFlare || m_UseAnamorphicFlare || m_UseStarFlare; + + string combineShaderPath = "Hidden/Ultimate/BloomCombine"; + if (useDustOrFlare) + combineShaderPath = "Hidden/Ultimate/BloomCombineFlareDirt"; + + LoadShader(ref m_CombineMaterial, ref m_CombineShader, combineShaderPath); + } + + private Material CreateMaterial(Shader shader) + { + if (!shader) + return null; + Material m = new Material(shader); + m.hideFlags = HideFlags.HideAndDontSave; + return m; + } + + void OnDisable() + { + ForceShadersReload(); + if (m_FlareSpriteRenderer != null) + { + m_FlareSpriteRenderer.Clear(ref m_BokehMeshes); + m_FlareSpriteRenderer = null; + } + } + + public void ForceShadersReload() + { + DestroyMaterial(m_FlareMaterial); m_FlareMaterial = null; m_FlareShader = null; + DestroyMaterial(m_SamplingMaterial); m_SamplingMaterial = null; m_SamplingShader = null; + DestroyMaterial(m_CombineMaterial); m_CombineMaterial = null; m_CombineShader = null; + DestroyMaterial(m_BrightpassMaterial); m_BrightpassMaterial = null; m_BrightpassShader = null; + DestroyMaterial(m_FlareBokehMaterial); m_FlareBokehMaterial = null; m_FlareBokehShader = null; + DestroyMaterial(m_FlareMaskMaterial); m_FlareMaskMaterial = null; m_FlareMaskShader = null; + DestroyMaterial(m_MixerMaterial); m_MixerMaterial = null; m_MixerShader = null; + } + + + private RenderTexture[] m_DownSamples; + private RenderTexture[] m_UpSamples; + + int GetNeededDownsamples() + { + int m = Mathf.Max(m_DownscaleCount, m_UseAnamorphicFlare ? m_AnamorphicDownscaleCount : 0); + m = Mathf.Max(m, m_UseLensFlare ? GetGhostBokehLayer() + 1 : 0); + m = Mathf.Max(m, m_UseStarFlare ? m_StarDownscaleCount : 0); + + return m; + } + + private RenderTextureFormat m_Format; + + + bool[] m_BufferUsage; + void ComputeBufferOptimization() + { + if (m_BufferUsage == null) + m_BufferUsage = new bool[m_DownSamples.Length]; + if (m_BufferUsage.Length != m_DownSamples.Length) + m_BufferUsage = new bool[m_DownSamples.Length]; + + for (int i = 0; i < m_BufferUsage.Length; ++i) + m_BufferUsage[i] = false; + + for (int i = 0; i < m_BufferUsage.Length; ++i) + m_BufferUsage[i] = m_BloomUsages[i] ? true : m_BufferUsage[i]; + + if (m_UseAnamorphicFlare) + for (int i = 0; i < m_BufferUsage.Length; ++i) + m_BufferUsage[i] = m_AnamorphicBloomUsages[i] ? true : m_BufferUsage[i]; + + if (m_UseStarFlare) + for (int i = 0; i < m_BufferUsage.Length; ++i) + m_BufferUsage[i] = m_StarBloomUsages[i] ? true : m_BufferUsage[i]; + } + + int GetGhostBokehLayer() + { + if (m_UseBokehFlare && m_FlareShape != null) + { + if (m_BokehFlareQuality == BokehFlareQuality.VeryHigh) + return 1; + if (m_BokehFlareQuality == BokehFlareQuality.High) + return 2; + if (m_BokehFlareQuality == BokehFlareQuality.Medium) + return 3; + if (m_BokehFlareQuality == BokehFlareQuality.Low) + return 4; + } + return 0;// Ghost + } + + BlurSampleCount GetUpsamplingSize() + { + if (m_SamplingMode == SamplingMode.Fixed) + { + BlurSampleCount upsamplingCount = BlurSampleCount.ThrirtyOne; + if (m_UpsamplingQuality == BloomSamplingQuality.VerySmallKernel) + upsamplingCount = BlurSampleCount.Nine; + else if (m_UpsamplingQuality == BloomSamplingQuality.SmallKernel) + upsamplingCount = BlurSampleCount.Thirteen; + else if (m_UpsamplingQuality == BloomSamplingQuality.MediumKernel) + upsamplingCount = BlurSampleCount.Seventeen; + else if (m_UpsamplingQuality == BloomSamplingQuality.LargeKernel) + upsamplingCount = BlurSampleCount.TwentyThree; + else if (m_UpsamplingQuality == BloomSamplingQuality.LargerKernel) + upsamplingCount = BlurSampleCount.TwentySeven; + return upsamplingCount; + } + + float pixelCount = Screen.height;//Screen.width * Screen.height; + int nearestIdx = 0; + float nearestDist = float.MaxValue; + for (int i = 0; i < m_ResSamplingPixelCount.Length; ++i) + { + float dist = Math.Abs(pixelCount - m_ResSamplingPixelCount[i]); + if (dist < nearestDist) + { + nearestDist = dist; + nearestIdx = i; + } + } + + if (nearestIdx == 0) + return BlurSampleCount.Nine; + if (nearestIdx == 1) + return BlurSampleCount.Thirteen; + if (nearestIdx == 2) + return BlurSampleCount.Seventeen; + if (nearestIdx == 3) + return BlurSampleCount.TwentyThree; + if (nearestIdx == 4) + return BlurSampleCount.TwentySeven; + + return BlurSampleCount.ThrirtyOne; + } + + + public void ComputeResolutionRelativeData() + { + float currentRes = m_SamplingMinHeight; + float currentSampling = 9.0f; + for (int i = 0; i < m_ResSamplingPixelCount.Length; ++i) + { + m_ResSamplingPixelCount[i] = currentRes; + + float nextSampling = currentSampling + 4.0f; + float ratio = nextSampling / currentSampling; + currentRes *= ratio; + currentSampling = nextSampling; + } + } + + void OnRenderImage(RenderTexture source, RenderTexture destination) + { + + // Determine Texture Format + bool doHdr = false; + if (m_HDR == HDRBloomMode.Auto) + doHdr = source.format == RenderTextureFormat.ARGBHalf && GetComponent().hdr; + else + doHdr = m_HDR == HDRBloomMode.On; + + m_Format = (doHdr) ? RenderTextureFormat.ARGBHalf : RenderTextureFormat.Default; + + + if (m_DownSamples != null) + { + if (m_DownSamples.Length != GetNeededDownsamples()) + { + OnDisable(); + } + } + + + if (m_LastDownscaleCount != m_DownscaleCount + || m_LastAnamorphicDownscaleCount != m_AnamorphicDownscaleCount + || m_LastStarDownscaleCount != m_StarDownscaleCount) + { + OnDisable(); + } + m_LastDownscaleCount = m_DownscaleCount; + m_LastAnamorphicDownscaleCount = m_AnamorphicDownscaleCount; + m_LastStarDownscaleCount = m_StarDownscaleCount; + + CreateMaterials(); + + + + if (m_DirectDownSample || m_DirectUpsample) + ComputeBufferOptimization(); + + bool debugFlareShape = false; + + if (m_SamplingMode == SamplingMode.HeightRelative) + ComputeResolutionRelativeData(); + + + ////////////////////////////////// + // 1. Bright pass + ////////////////////////////////// + RenderTexture brightTexture = RenderTexture.GetTemporary(source.width, source.height, 0, m_Format); + brightTexture.filterMode = FilterMode.Bilinear; + + if (m_IntensityManagement == BloomIntensityManagement.Threshold) + BrightPass(source, brightTexture, m_BloomThreshhold * m_BloomThreshholdColor); + else + { + m_BloomCurve.UpdateCoefficients(); + Graphics.Blit(source, brightTexture); + } + + + + ////////////////////////////////// + // 2. Downscale source texture + ////////////////////////////////// + if (m_IntensityManagement == BloomIntensityManagement.Threshold) + CachedDownsample(brightTexture, m_DownSamples, null, doHdr); + else + CachedDownsample(brightTexture, m_DownSamples, m_BloomCurve, doHdr); + + ////////////////////////////////// + // 3. Upsample + ////////////////////////////////// + // Upsampling quality + BlurSampleCount upsamplingCount = GetUpsamplingSize(); + // Upsample + CachedUpsample(m_DownSamples, m_UpSamples, source.width, source.height, upsamplingCount); + // Release unused upsamples + /* if (m_DirectUpsample) + { + for (int i = 1; i < m_UpSamples.Length; ++i) + if (m_BufferUsage[i]) + RenderTexture.ReleaseTemporary(m_UpSamples[i]); + } + else*/ + + + //for (int i = 1; i < m_UpSamples.Length; ++i) + // RenderTexture.ReleaseTemporary(m_UpSamples[i]); + + + ////////////////////////////////// + // Optional: Ghost lens flare + ////////////////////////////////// + + Texture flareRT = Texture2D.blackTexture; + RenderTexture flareShapeBuffer = null; + if (m_UseLensFlare) + { + int bokehQuality = GetGhostBokehLayer(); + + int flareWidth = source.width / (int)Mathf.Pow(2.0f, bokehQuality); + int flareHeigth = source.height / (int)Mathf.Pow(2.0f, bokehQuality); + + if (m_FlareShape != null && m_UseBokehFlare) + { + float size = 15.0f; + if (m_BokehFlareQuality == BokehFlareQuality.Medium) + size *= 2; + if (m_BokehFlareQuality == BokehFlareQuality.High) + size *= 4; + if (m_BokehFlareQuality == BokehFlareQuality.VeryHigh) + size *= 8; + + size *= m_BokehScale; + m_FlareSpriteRenderer.SetMaterial(m_FlareBokehMaterial); + m_FlareSpriteRenderer.RebuildMeshIfNeeded(flareWidth, flareHeigth, 1.0f / flareWidth * size, 1.0f / flareHeigth * size, ref m_BokehMeshes); + m_FlareSpriteRenderer.SetTexture(m_FlareShape); + + flareShapeBuffer = RenderTexture.GetTemporary(source.width / 4 , source.height / 4 , 0, m_Format); + + int bokehTargetSize = bokehQuality; + RenderTexture flareBrightTexture = RenderTexture.GetTemporary(source.width / (int)Mathf.Pow(2.0f, (bokehTargetSize + 1)), source.height / (int)Mathf.Pow(2.0f, (bokehTargetSize + 1)), 0, m_Format); + BrightPass(m_DownSamples[bokehQuality], flareBrightTexture, m_FlareTreshold * Vector4.one); + m_FlareSpriteRenderer.RenderFlare(flareBrightTexture, flareShapeBuffer, m_UseBokehFlare ? 1.0f : m_FlareIntensity, ref m_BokehMeshes); + RenderTexture.ReleaseTemporary(flareBrightTexture); + + RenderTexture maskFlare = RenderTexture.GetTemporary(flareShapeBuffer.width, flareShapeBuffer.height, 0, m_Format); + m_FlareMaskMaterial.SetTexture("_MaskTex", m_FlareMask); + Graphics.Blit(flareShapeBuffer, maskFlare, m_FlareMaskMaterial, 0); + + RenderTexture.ReleaseTemporary(flareShapeBuffer); flareShapeBuffer = null; + RenderFlares(maskFlare, source, ref flareRT); + RenderTexture.ReleaseTemporary(maskFlare); + } + else + { + //BrightPassWithMask(source, brightTexture, m_FlareTreshold * Vector4.one, m_FlareMask); + //RenderFlares( brightTexture, source, ref flareRT); + int ghostLayer = GetGhostBokehLayer(); + RenderTexture flareSource = m_DownSamples[ghostLayer]; + RenderTexture flareBrightTexture = RenderTexture.GetTemporary(flareSource.width, flareSource.height, 0, m_Format); + + BrightPassWithMask(m_DownSamples[ghostLayer], flareBrightTexture, m_FlareTreshold * Vector4.one, m_FlareMask); + RenderFlares(flareBrightTexture, source, ref flareRT); + + RenderTexture.ReleaseTemporary(flareBrightTexture); + } + + + } + + if (!m_UseLensFlare && m_FlareSpriteRenderer != null) + m_FlareSpriteRenderer.Clear(ref m_BokehMeshes); + + ////////////////////////////////// + // Optional: Anamorphic lens flare + ////////////////////////////////// + if (m_UseAnamorphicFlare) + { + RenderTexture anamorphicResult = RenderStripe(m_DownSamples, upsamplingCount, source.width, source.height, FlareStripeType.Anamorphic); + + if (anamorphicResult != null) + { + if (m_UseLensFlare) + { + RenderTextureAdditive(anamorphicResult, (RenderTexture)flareRT, 1.0f); + RenderTexture.ReleaseTemporary(anamorphicResult); + } + else + { + flareRT = anamorphicResult; + } + } + } + + ////////////////////////////////// + // Optional: Star lens flare + ////////////////////////////////// + if (m_UseStarFlare) + { + //RenderTexture starResult = RenderStar(m_DownSamples, upsamplingCount, source.width, source.height); + RenderTexture starResult = null; + + if (m_StarBlurPass == 1) + { + starResult = RenderStripe(m_DownSamples, upsamplingCount, source.width, source.height, FlareStripeType.Star); + + if (starResult != null) + { + if (m_UseLensFlare || m_UseAnamorphicFlare) + { + RenderTextureAdditive(starResult, (RenderTexture)flareRT, m_StarFlareIntensity); + } + else + { + flareRT = RenderTexture.GetTemporary(source.width, source.height, 0, m_Format); + BlitIntensity(starResult, (RenderTexture)flareRT, m_StarFlareIntensity); + } + + RenderTexture.ReleaseTemporary(starResult); + } + } + else + { + if (m_UseLensFlare || m_UseAnamorphicFlare) + { + starResult = RenderStripe(m_DownSamples, upsamplingCount, source.width, source.height, FlareStripeType.DiagonalUpright); + if (starResult != null) + { + RenderTextureAdditive(starResult, (RenderTexture)flareRT, m_StarFlareIntensity); + RenderTexture.ReleaseTemporary(starResult); + starResult = RenderStripe(m_DownSamples, upsamplingCount, source.width, source.height, FlareStripeType.DiagonalUpleft); + + RenderTextureAdditive(starResult, (RenderTexture)flareRT, m_StarFlareIntensity); + RenderTexture.ReleaseTemporary(starResult); + } + } + else + { + starResult = RenderStripe(m_DownSamples, upsamplingCount, source.width, source.height, FlareStripeType.DiagonalUpleft); + if (starResult != null) + { + RenderTexture tmpStarResult = RenderStripe(m_DownSamples, upsamplingCount, source.width, source.height, FlareStripeType.DiagonalUpright); + CombineAdditive(tmpStarResult, starResult, m_StarFlareIntensity, m_StarFlareIntensity); + RenderTexture.ReleaseTemporary(tmpStarResult); + + flareRT = starResult; + } + } + } + + + } + + // Release downsamples + if (m_DirectDownSample) + for (int i = 0; i < m_DownSamples.Length; ++i) + { + if (m_BufferUsage[i]) + RenderTexture.ReleaseTemporary(m_DownSamples[i]); + } + else + for (int i = 0; i < m_DownSamples.Length; ++i) + RenderTexture.ReleaseTemporary(m_DownSamples[i]); + + ////////////////////////////////// + // Combine pass + ////////////////////////////////// + m_CombineMaterial.SetFloat("_Intensity", m_BloomIntensity); + + m_CombineMaterial.SetFloat("_FlareIntensity", m_FlareIntensity); + m_CombineMaterial.SetTexture("_ColorBuffer", source); + m_CombineMaterial.SetTexture("_FlareTexture", flareRT); + m_CombineMaterial.SetTexture("_AdditiveTexture", m_UseLensDust ? m_DustTexture : Texture2D.whiteTexture); + m_CombineMaterial.SetTexture("_brightTexture", brightTexture); + if (m_UseLensDust) + { + m_CombineMaterial.SetFloat("_DirtIntensity", m_DustIntensity); + m_CombineMaterial.SetFloat("_DirtLightIntensity", m_DirtLightIntensity); + } + else + { + m_CombineMaterial.SetFloat("_DirtIntensity", 1.0f); + m_CombineMaterial.SetFloat("_DirtLightIntensity", 0.0f); + } + + + if (m_BlendMode == BlendMode.SCREEN) + { + m_CombineMaterial.SetFloat("_ScreenMaxIntensity", m_ScreenMaxIntensity); + } + + if (m_InvertImage) + Graphics.Blit(m_LastBloomUpsample, destination, m_CombineMaterial, 1); + else + Graphics.Blit(m_LastBloomUpsample, destination, m_CombineMaterial, 0); + + + for (int i = 0; i < m_UpSamples.Length; ++i) + if (m_UpSamples[i] != null) + RenderTexture.ReleaseTemporary(m_UpSamples[i]); + + //Graphics.Blit(m_UpSamples[0], destination); + + ////////////////////////////////// + // Cleaning + ////////////////////////////////// + + if (debugFlareShape) + Graphics.Blit(flareShapeBuffer, destination); + + + if (m_UseLensFlare || m_UseAnamorphicFlare || m_UseStarFlare) + if (flareRT != null && flareRT is RenderTexture) + RenderTexture.ReleaseTemporary((RenderTexture)flareRT); + + RenderTexture.ReleaseTemporary(brightTexture); + + if (m_FlareShape != null && m_UseBokehFlare && flareShapeBuffer != null) + { + RenderTexture.ReleaseTemporary(flareShapeBuffer); + } + } + + RenderTexture RenderStar(RenderTexture[] sources, BlurSampleCount upsamplingCount, int sourceWidth, int sourceHeight) + { + for (int i = m_StarUpscales.Length - 1; i >= 0; --i) + { + m_StarUpscales[i] = RenderTexture.GetTemporary(sourceWidth / (int)Mathf.Pow(2.0f, i), sourceHeight / (int)Mathf.Pow(2.0f, i), 0, m_Format); + m_StarUpscales[i].filterMode = FilterMode.Bilinear; + + float horizontalBlur = 1.0f / sources[i].width; + float verticalBlur = 1.0f / sources[i].height; + + if (i < m_StarDownscaleCount - 1) + GaussianBlur2(sources[i], m_StarUpscales[i], horizontalBlur * m_StarScale, verticalBlur * m_StarScale, m_StarUpscales[i + 1], upsamplingCount, Color.white, 1.0f); + else + GaussianBlur2(sources[i], m_StarUpscales[i], horizontalBlur * m_StarScale, verticalBlur * m_StarScale, null, upsamplingCount, Color.white, 1.0f); + } + + for (int i = 1; i < m_StarUpscales.Length; ++i) + if (m_StarUpscales[i] != null) + RenderTexture.ReleaseTemporary(m_StarUpscales[i]); + + return m_StarUpscales[0]; + + } + + delegate void BlurFunction(RenderTexture source, RenderTexture destination, float horizontalBlur, float verticalBlur, RenderTexture additiveTexture, BlurSampleCount sampleCount, Color tint, float intensity); + + RenderTexture RenderStripe(RenderTexture[] sources, BlurSampleCount upsamplingCount, int sourceWidth, int sourceHeight, FlareStripeType type) + { + + + + //BlurFunction blur = GaussianBlur1; + //int nbUpscales = m_AnamorphicUpscales.Length; + RenderTexture[] upscales = m_AnamorphicUpscales; + bool[] usages = m_AnamorphicBloomUsages; + float[] intensities = m_AnamorphicBloomIntensities; + Color[] tints = m_AnamorphicBloomColors; + bool antiJitter = m_AnamorphicSmallVerticalBlur; + float blurPass = m_AnamorphicBlurPass; + float scale = m_AnamorphicScale; + float globalIntensity = m_AnamorphicFlareIntensity; + + float horiMul = 1.0f; + float vertiMul = 0.0f; + + if (m_AnamorphicDirection == AnamorphicDirection.Vertical) + { + horiMul = 0.0f; + vertiMul = 1.0f; + } + + if (type != FlareStripeType.Anamorphic) + { + // if (type == FlareStripeType.Star) + // blur = GaussianBlur2; + + //nbUpscales = m_StarUpscales.Length; + upscales = m_StarUpscales; + usages = m_StarBloomUsages; + intensities = m_StarBloomIntensities; + tints = m_StarBloomColors; + antiJitter = false; + blurPass = m_StarBlurPass; + scale = m_StarScale; + globalIntensity = m_StarFlareIntensity; + + if (type == FlareStripeType.DiagonalUpleft) + vertiMul = -1.0f; + else + vertiMul = 1.0f; + } + + for (int i = 0; i < upscales.Length; ++i) + upscales[i] = null; + + RenderTexture additiveTexture = null; + for (int i = upscales.Length - 1; i >= 0; --i) + { + if (sources[i] == null && m_DirectUpsample) + continue; + if (!usages[i] && m_DirectUpsample) + continue; + + + upscales[i] = RenderTexture.GetTemporary(sourceWidth / (int)Mathf.Pow(2.0f, i), sourceHeight / (int)Mathf.Pow(2.0f, i), 0, m_Format); + upscales[i].filterMode = FilterMode.Bilinear; + + float horizontalBlur = 1.0f / upscales[i].width; + float verticalBlur = 1.0f / upscales[i].height; + + RenderTexture source = sources[i]; + RenderTexture dest = upscales[i]; + + if (!usages[i]) + { + if (additiveTexture != null) + { + if (antiJitter) + GaussianBlur1(additiveTexture, dest, m_AnamorphicDirection == AnamorphicDirection.Vertical ? horizontalBlur : 0.0f, m_AnamorphicDirection == AnamorphicDirection.Horizontal ? verticalBlur : 0.0f, null, BlurSampleCount.FourSimple, Color.white, 1.0f); + else + Graphics.Blit(additiveTexture, dest); + } + else + Graphics.Blit(Texture2D.blackTexture, dest); + + additiveTexture = upscales[i]; + continue; + } + + RenderTexture antiJitterBuffer = null; + if (antiJitter && additiveTexture != null) + { + antiJitterBuffer = RenderTexture.GetTemporary(dest.width, dest.height, 0, m_Format); + GaussianBlur1(additiveTexture, antiJitterBuffer, m_AnamorphicDirection == AnamorphicDirection.Vertical ? horizontalBlur : 0.0f, m_AnamorphicDirection == AnamorphicDirection.Horizontal ? verticalBlur : 0.0f, null, BlurSampleCount.FourSimple, Color.white, 1.0f); + additiveTexture = antiJitterBuffer; + } + + if (blurPass == 1) + { + if (type != FlareStripeType.Anamorphic) + GaussianBlur2(source, dest, horizontalBlur * scale * horiMul, verticalBlur * scale * vertiMul, additiveTexture, upsamplingCount, tints[i], intensities[i] * globalIntensity); + else + GaussianBlur1(source, dest, horizontalBlur * scale * horiMul, verticalBlur * scale * vertiMul, additiveTexture, upsamplingCount, tints[i], intensities[i] * globalIntensity); + } + else + { + RenderTexture tmp = RenderTexture.GetTemporary(dest.width, dest.height, 0, m_Format); + bool lastTargetIsTmp = false; + for (int j = 0; j < blurPass; ++j) + { + RenderTexture finalAdditiveTexture = (j == blurPass - 1) ? additiveTexture : null; + + if (j == 0) + { + if (type != FlareStripeType.Anamorphic) + GaussianBlur2(source, tmp, horizontalBlur * scale * horiMul, verticalBlur * scale * vertiMul, finalAdditiveTexture, upsamplingCount, tints[i], intensities[i] * globalIntensity); + else + GaussianBlur1(source, tmp, horizontalBlur * scale * horiMul, verticalBlur * scale * vertiMul, finalAdditiveTexture, upsamplingCount, tints[i], intensities[i] * globalIntensity); + } + else + { + horizontalBlur = 1.0f / dest.width; + verticalBlur = 1.0f / dest.height; + if (j % 2 == 1) + { + if (type != FlareStripeType.Anamorphic) + GaussianBlur2(tmp, dest, horizontalBlur * scale * horiMul * 1.5f, verticalBlur * scale * vertiMul * 1.5f, finalAdditiveTexture, upsamplingCount, tints[i], intensities[i] * globalIntensity); + else + GaussianBlur1(tmp, dest, horizontalBlur * scale * horiMul * 1.5f, verticalBlur * scale * vertiMul * 1.5f, finalAdditiveTexture, upsamplingCount, tints[i], intensities[i] * globalIntensity); + lastTargetIsTmp = false; + } + else + { + if (type != FlareStripeType.Anamorphic) + GaussianBlur2(dest, tmp, horizontalBlur * scale * horiMul * 1.5f, verticalBlur * scale * vertiMul * 1.5f, finalAdditiveTexture, upsamplingCount, tints[i], intensities[i] * globalIntensity); + else + GaussianBlur1(dest, tmp, horizontalBlur * scale * horiMul * 1.5f, verticalBlur * scale * vertiMul * 1.5f, finalAdditiveTexture, upsamplingCount, tints[i], intensities[i] * globalIntensity); + lastTargetIsTmp = true; + } + } + } + if (lastTargetIsTmp) + Graphics.Blit(tmp, dest); + + if (antiJitterBuffer != null) + RenderTexture.ReleaseTemporary(antiJitterBuffer); + + + RenderTexture.ReleaseTemporary(tmp); + + } + + additiveTexture = upscales[i]; + } + + + + RenderTexture firstFound = null; + for (int i = 0; i < upscales.Length; ++i) + if (upscales[i] != null) + if (firstFound == null) firstFound = upscales[i]; + else RenderTexture.ReleaseTemporary(upscales[i]); + + return firstFound; + } + + void RenderFlares(RenderTexture brightTexture, RenderTexture source,ref Texture flareRT) + { + + flareRT = RenderTexture.GetTemporary(source.width, source.height, 0, m_Format); + flareRT.filterMode = FilterMode.Bilinear; + m_FlareMaterial.SetVector("_FlareScales", m_FlareScales * m_FlareGlobalScale); + m_FlareMaterial.SetVector("_FlareScalesNear", m_FlareScalesNear * m_FlareGlobalScale); + m_FlareMaterial.SetVector("_FlareTint0", m_FlareTint0); + m_FlareMaterial.SetVector("_FlareTint1", m_FlareTint1); + m_FlareMaterial.SetVector("_FlareTint2", m_FlareTint2); + m_FlareMaterial.SetVector("_FlareTint3", m_FlareTint3); + m_FlareMaterial.SetVector("_FlareTint4", m_FlareTint4); + m_FlareMaterial.SetVector("_FlareTint5", m_FlareTint5); + m_FlareMaterial.SetVector("_FlareTint6", m_FlareTint6); + m_FlareMaterial.SetVector("_FlareTint7", m_FlareTint7); + m_FlareMaterial.SetFloat("_Intensity", m_FlareIntensity); + //Graphics.Blit(brightTexture, (RenderTexture)flareRT, m_BloomMaterial, 8); + if (m_FlareRendering == FlareRendering.Sharp) + { + RenderTexture HalfTmp = RenderTexture.GetTemporary(source.width / 2, source.height / 2, 0, m_Format); + HalfTmp.filterMode = FilterMode.Bilinear; + + RenderSimple(brightTexture, HalfTmp, 1.0f / brightTexture.width, 1.0f / brightTexture.height, SimpleSampleCount.Four); + + Graphics.Blit(HalfTmp, (RenderTexture)flareRT, m_FlareMaterial, 0); + + RenderTexture.ReleaseTemporary(HalfTmp); + + return; + } + + // Blur flare + + if (m_FlareBlurQuality == FlareBlurQuality.Fast) + { + RenderTexture HalfFlareRT = RenderTexture.GetTemporary(brightTexture.width / 2, brightTexture.height / 2, 0, m_Format); + HalfFlareRT.filterMode = FilterMode.Bilinear; + + RenderTexture QuarterFlareRT = RenderTexture.GetTemporary(brightTexture.width / 4, brightTexture.height / 4, 0, m_Format); + QuarterFlareRT.filterMode = FilterMode.Bilinear; + + Graphics.Blit(brightTexture, HalfFlareRT, m_FlareMaterial, 0); + + if (m_FlareRendering == FlareRendering.Blurred) + { + GaussianBlurSeparate(HalfFlareRT, (RenderTexture)QuarterFlareRT, 1.0f / HalfFlareRT.width, 1.0f / HalfFlareRT.height, null, BlurSampleCount.Thirteen, Color.white, 1.0f); + RenderSimple(QuarterFlareRT, (RenderTexture)flareRT, 1.0f / QuarterFlareRT.width, 1.0f / QuarterFlareRT.height, SimpleSampleCount.Four); + } + else if (m_FlareRendering == FlareRendering.MoreBlurred) + { + GaussianBlurSeparate(HalfFlareRT, (RenderTexture)QuarterFlareRT, 1.0f / HalfFlareRT.width, 1.0f / HalfFlareRT.height, null, BlurSampleCount.ThrirtyOne, Color.white, 1.0f); + RenderSimple(QuarterFlareRT, (RenderTexture)flareRT, 1.0f / QuarterFlareRT.width, 1.0f / QuarterFlareRT.height, SimpleSampleCount.Four); + } + RenderTexture.ReleaseTemporary(HalfFlareRT); + RenderTexture.ReleaseTemporary(QuarterFlareRT); + return; + } + else if (m_FlareBlurQuality == FlareBlurQuality.Normal) + { + RenderTexture HalfFlareRT = RenderTexture.GetTemporary(brightTexture.width / 2, brightTexture.height / 2, 0, m_Format); + HalfFlareRT.filterMode = FilterMode.Bilinear; + + RenderTexture QuarterFlareRT = RenderTexture.GetTemporary(brightTexture.width / 4, brightTexture.height / 4, 0, m_Format); + QuarterFlareRT.filterMode = FilterMode.Bilinear; + + RenderTexture QuarterFlareRT2 = RenderTexture.GetTemporary(brightTexture.width / 4, brightTexture.height / 4, 0, m_Format); + QuarterFlareRT2.filterMode = FilterMode.Bilinear; + + + RenderSimple(brightTexture, HalfFlareRT, 1.0f / brightTexture.width, 1.0f / brightTexture.height, SimpleSampleCount.Four); + RenderSimple(HalfFlareRT, QuarterFlareRT, 1.0f / HalfFlareRT.width, 1.0f / HalfFlareRT.height, SimpleSampleCount.Four); + + Graphics.Blit(QuarterFlareRT, QuarterFlareRT2, m_FlareMaterial, 0); + + + if (m_FlareRendering == FlareRendering.Blurred) + { + GaussianBlurSeparate(QuarterFlareRT2, (RenderTexture)QuarterFlareRT, 1.0f / QuarterFlareRT.width, 1.0f / QuarterFlareRT.height, null, BlurSampleCount.Thirteen, Color.white, 1.0f); + RenderSimple(QuarterFlareRT, (RenderTexture)flareRT, 1.0f / QuarterFlareRT.width, 1.0f / QuarterFlareRT.height, SimpleSampleCount.Four); + } + else if (m_FlareRendering == FlareRendering.MoreBlurred) + { + GaussianBlurSeparate(QuarterFlareRT2, (RenderTexture)QuarterFlareRT, 1.0f / QuarterFlareRT.width, 1.0f / QuarterFlareRT.height, null, BlurSampleCount.ThrirtyOne, Color.white, 1.0f); + RenderSimple(QuarterFlareRT, (RenderTexture)flareRT, 1.0f / QuarterFlareRT.width, 1.0f / QuarterFlareRT.height, SimpleSampleCount.Four); + } + + + RenderTexture.ReleaseTemporary(HalfFlareRT); + RenderTexture.ReleaseTemporary(QuarterFlareRT); + RenderTexture.ReleaseTemporary(QuarterFlareRT2); + } + else if (m_FlareBlurQuality == FlareBlurQuality.High) + { + RenderTexture HalfFlareRT = RenderTexture.GetTemporary(brightTexture.width / 2, brightTexture.height / 2, 0, m_Format); + HalfFlareRT.filterMode = FilterMode.Bilinear; + + RenderTexture QuarterFlareRT = RenderTexture.GetTemporary(HalfFlareRT.width / 2, HalfFlareRT.height / 2, 0, m_Format); + QuarterFlareRT.filterMode = FilterMode.Bilinear; + + RenderTexture HFlareRT1 = RenderTexture.GetTemporary(QuarterFlareRT.width / 2, QuarterFlareRT.height / 2, 0, m_Format); + HFlareRT1.filterMode = FilterMode.Bilinear; + + RenderTexture HFlareRT2 = RenderTexture.GetTemporary(QuarterFlareRT.width / 2, QuarterFlareRT.height / 2, 0, m_Format); + HFlareRT2.filterMode = FilterMode.Bilinear; + + + RenderSimple(brightTexture, HalfFlareRT, 1.0f / brightTexture.width, 1.0f / brightTexture.height, SimpleSampleCount.Four); + RenderSimple(HalfFlareRT, QuarterFlareRT, 1.0f / HalfFlareRT.width, 1.0f / HalfFlareRT.height, SimpleSampleCount.Four); + RenderSimple(QuarterFlareRT, HFlareRT1, 1.0f / QuarterFlareRT.width, 1.0f / QuarterFlareRT.height, SimpleSampleCount.Four); + + Graphics.Blit(HFlareRT1, HFlareRT2, m_FlareMaterial, 0); + + + if (m_FlareRendering == FlareRendering.Blurred) + { + GaussianBlurSeparate(HFlareRT2, (RenderTexture)HFlareRT1, 1.0f / HFlareRT1.width, 1.0f / HFlareRT1.height, null, BlurSampleCount.Thirteen, Color.white, 1.0f); + RenderSimple(HFlareRT1, (RenderTexture)flareRT, 1.0f / HFlareRT1.width, 1.0f / HFlareRT1.height, SimpleSampleCount.Four); + } + else if (m_FlareRendering == FlareRendering.MoreBlurred) + { + GaussianBlurSeparate(HFlareRT2, (RenderTexture)HFlareRT1, 1.0f / HFlareRT1.width, 1.0f / HFlareRT1.height, null, BlurSampleCount.ThrirtyOne, Color.white, 1.0f); + RenderSimple(HFlareRT1, (RenderTexture)flareRT, 1.0f / HFlareRT1.width, 1.0f / HFlareRT1.height, SimpleSampleCount.Four); + } + + + RenderTexture.ReleaseTemporary(HalfFlareRT); + RenderTexture.ReleaseTemporary(QuarterFlareRT); + RenderTexture.ReleaseTemporary(HFlareRT1); + RenderTexture.ReleaseTemporary(HFlareRT2); + } + + + + } + + RenderTexture m_LastBloomUpsample; + + void CachedUpsample(RenderTexture[] sources, RenderTexture[] destinations, int originalWidth, int originalHeight, BlurSampleCount upsamplingCount) + { + RenderTexture lastUpsample = null; + + for (int i = 0; i < m_UpSamples.Length; ++i) + m_UpSamples[i] = null; + + for (int i = destinations.Length - 1; i >= 0; --i) + { + if (m_BloomUsages[i] || !m_DirectUpsample) + { + m_UpSamples[i] = RenderTexture.GetTemporary(originalWidth / (int)Mathf.Pow(2.0f, i), originalHeight / (int)Mathf.Pow(2.0f, i), 0, m_Format); + m_UpSamples[i].filterMode = FilterMode.Bilinear; + } + + float mul = 1.0f; + + if (m_BloomUsages[i]) + { + float horizontalBlur = 1.0f / sources[i].width; + float verticalBlur = 1.0f / sources[i].height; + + GaussianBlurSeparate(m_DownSamples[i], m_UpSamples[i], horizontalBlur * mul, verticalBlur, lastUpsample, upsamplingCount, m_BloomColors[i], m_BloomIntensities[i]); + } + else + { + if (i < m_DownscaleCount - 1) + { + if (!m_DirectUpsample) + RenderSimple(lastUpsample, m_UpSamples[i], 1.0f / m_UpSamples[i].width, 1.0f / m_UpSamples[i].height, SimpleSampleCount.Four); + //Graphics.Blit(m_UpSamples[i + 1], m_UpSamples[i]); + } + else + Graphics.Blit(Texture2D.blackTexture, m_UpSamples[i]); + } + + if (m_BloomUsages[i] || !m_DirectUpsample) + lastUpsample = m_UpSamples[i]; + } + + m_LastBloomUpsample = lastUpsample; + } + + void CachedDownsample(RenderTexture source, RenderTexture[] destinations, DeluxeFilmicCurve intensityCurve, bool hdr) + { + int downscaleCount = destinations.Length; + + RenderTexture currentSource = source; + + bool filmicCurveDone = false; + + for (int i = 0; i < downscaleCount; ++i) + { + if (m_DirectDownSample) + { + if (!m_BufferUsage[i]) + continue; + } + + destinations[i] = RenderTexture.GetTemporary(source.width / (int)Mathf.Pow(2.0f, (i + 1)), source.height / (int)Mathf.Pow(2.0f, (i + 1)), 0, m_Format); + destinations[i].filterMode = FilterMode.Bilinear; + + RenderTexture dest = destinations[i]; + float dist = 1.0f; + + float horizontalBlur = 1.0f / currentSource.width; + float verticalBlur = 1.0f / currentSource.height; + + // Render previous into next + { + if (intensityCurve != null && !filmicCurveDone) + { + intensityCurve.StoreK(); + m_SamplingMaterial.SetFloat("_CurveExposure", intensityCurve.GetExposure()); + m_SamplingMaterial.SetFloat("_K", intensityCurve.m_k); + m_SamplingMaterial.SetFloat("_Crossover", intensityCurve.m_CrossOverPoint); + m_SamplingMaterial.SetVector("_Toe", intensityCurve.m_ToeCoef); + m_SamplingMaterial.SetVector("_Shoulder", intensityCurve.m_ShoulderCoef); + // m_SamplingMaterial.SetFloat("_MaxValue", intensityCurve.m_WhitePoint); + + + float colorRange = hdr ? 2.0f : 1.0f; + m_SamplingMaterial.SetFloat("_MaxValue", colorRange); + + horizontalBlur = 1.0f / currentSource.width; + verticalBlur = 1.0f / currentSource.height; + + if (m_TemporalStableDownsampling) + RenderSimple(currentSource, dest, horizontalBlur * dist, verticalBlur * dist, SimpleSampleCount.ThirteenTemporalCurve); + else + RenderSimple(currentSource, dest, horizontalBlur * dist, verticalBlur * dist, SimpleSampleCount.FourCurve); + filmicCurveDone = true; + } + else + { + if (m_TemporalStableDownsampling) + RenderSimple(currentSource, dest, horizontalBlur * dist, verticalBlur * dist, SimpleSampleCount.ThirteenTemporal); + else + RenderSimple(currentSource, dest, horizontalBlur * dist, verticalBlur * dist, SimpleSampleCount.Four); + } + } + + + currentSource = destinations[i]; + + } + } + + + void BrightPass(RenderTexture source, RenderTexture destination, Vector4 treshold) + { + m_BrightpassMaterial.SetTexture("_MaskTex", Texture2D.whiteTexture); + m_BrightpassMaterial.SetVector("_Threshhold", treshold); + Graphics.Blit(source, destination, m_BrightpassMaterial, 0); + } + + void BrightPassWithMask(RenderTexture source, RenderTexture destination, Vector4 treshold, Texture mask) + { + m_BrightpassMaterial.SetTexture("_MaskTex", mask); + m_BrightpassMaterial.SetVector("_Threshhold", treshold); + Graphics.Blit(source, destination, m_BrightpassMaterial, 0); + } + + void RenderSimple(RenderTexture source, RenderTexture destination, float horizontalBlur, float verticalBlur, SimpleSampleCount sampleCount) + { + m_SamplingMaterial.SetVector("_OffsetInfos", new Vector4(horizontalBlur, verticalBlur, 0, 0)); + + if (sampleCount == SimpleSampleCount.Four) + Graphics.Blit(source, destination, m_SamplingMaterial, 0); + else if (sampleCount == SimpleSampleCount.Nine) + Graphics.Blit(source, destination, m_SamplingMaterial, 1); + else if (sampleCount == SimpleSampleCount.FourCurve) + Graphics.Blit(source, destination, m_SamplingMaterial, 5); + else if (sampleCount == SimpleSampleCount.ThirteenTemporal) + Graphics.Blit(source, destination, m_SamplingMaterial, 11); + else if (sampleCount == SimpleSampleCount.ThirteenTemporalCurve) + Graphics.Blit(source, destination, m_SamplingMaterial, 12); + } + + void GaussianBlur1(RenderTexture source, RenderTexture destination, float horizontalBlur, float verticalBlur, RenderTexture additiveTexture, BlurSampleCount sampleCount, Color tint, float intensity) + { + int passFromSamples = 2; + if (sampleCount == BlurSampleCount.Seventeen) + passFromSamples = 3; + if (sampleCount == BlurSampleCount.Nine) + passFromSamples = 4; + if (sampleCount == BlurSampleCount.NineCurve) + passFromSamples = 6; + if (sampleCount == BlurSampleCount.FourSimple) + passFromSamples = 7; + if (sampleCount == BlurSampleCount.Thirteen) + passFromSamples = 8; + if (sampleCount == BlurSampleCount.TwentyThree) + passFromSamples = 9; + if (sampleCount == BlurSampleCount.TwentySeven) + passFromSamples = 10; + + Texture additiveColor = null; + if (additiveTexture == null) + additiveColor = Texture2D.blackTexture; + else + additiveColor = additiveTexture; + + m_SamplingMaterial.SetTexture("_AdditiveTexture", additiveColor); + m_SamplingMaterial.SetVector("_OffsetInfos", new Vector4(horizontalBlur, verticalBlur, 0, 0)); + m_SamplingMaterial.SetVector("_Tint", tint); + m_SamplingMaterial.SetFloat("_Intensity", intensity); + Graphics.Blit(source, destination, m_SamplingMaterial, passFromSamples); + + } + + void GaussianBlur2(RenderTexture source, RenderTexture destination, float horizontalBlur, float verticalBlur, RenderTexture additiveTexture, BlurSampleCount sampleCount, Color tint, float intensity) + { + RenderTexture tmpTexture = RenderTexture.GetTemporary(destination.width, destination.height, destination.depth, destination.format); + tmpTexture.filterMode = FilterMode.Bilinear; + + int passFromSamples = 2; + if (sampleCount == BlurSampleCount.Seventeen) + passFromSamples = 3; + if (sampleCount == BlurSampleCount.Nine) + passFromSamples = 4; + if (sampleCount == BlurSampleCount.NineCurve) + passFromSamples = 6; + if (sampleCount == BlurSampleCount.FourSimple) + passFromSamples = 7; + if (sampleCount == BlurSampleCount.Thirteen) + passFromSamples = 8; + if (sampleCount == BlurSampleCount.TwentyThree) + passFromSamples = 9; + if (sampleCount == BlurSampleCount.TwentySeven) + passFromSamples = 10; + + Texture additiveColor = null; + + if (additiveTexture == null) + additiveColor = Texture2D.blackTexture; + else + additiveColor = additiveTexture; + + // First pass + m_SamplingMaterial.SetTexture("_AdditiveTexture", additiveColor); + m_SamplingMaterial.SetVector("_OffsetInfos", new Vector4(horizontalBlur, verticalBlur, 0, 0)); + m_SamplingMaterial.SetVector("_Tint", tint); + m_SamplingMaterial.SetFloat("_Intensity", intensity); + Graphics.Blit(source, tmpTexture, m_SamplingMaterial, passFromSamples); + + additiveColor = tmpTexture; + + // Second pass + m_SamplingMaterial.SetTexture("_AdditiveTexture", additiveColor); + m_SamplingMaterial.SetVector("_OffsetInfos", new Vector4(-horizontalBlur, verticalBlur, 0, 0)); + m_SamplingMaterial.SetVector("_Tint", tint); + m_SamplingMaterial.SetFloat("_Intensity", intensity); + Graphics.Blit(source, destination, m_SamplingMaterial, passFromSamples); + + RenderTexture.ReleaseTemporary(tmpTexture); + } + + void GaussianBlurSeparate(RenderTexture source, RenderTexture destination, float horizontalBlur, float verticalBlur, RenderTexture additiveTexture, BlurSampleCount sampleCount, Color tint, float intensity) + { + RenderTexture tmpTexture = RenderTexture.GetTemporary(destination.width, destination.height, destination.depth, destination.format); + tmpTexture.filterMode = FilterMode.Bilinear; + + int passFromSamples = 2; + if (sampleCount == BlurSampleCount.Seventeen) + passFromSamples = 3; + if (sampleCount == BlurSampleCount.Nine) + passFromSamples = 4; + if (sampleCount == BlurSampleCount.NineCurve) + passFromSamples = 6; + if (sampleCount == BlurSampleCount.FourSimple) + passFromSamples = 7; + if (sampleCount == BlurSampleCount.Thirteen) + passFromSamples = 8; + if (sampleCount == BlurSampleCount.TwentyThree) + passFromSamples = 9; + if (sampleCount == BlurSampleCount.TwentySeven) + passFromSamples = 10; + + // Vertical + m_SamplingMaterial.SetTexture("_AdditiveTexture", Texture2D.blackTexture); + m_SamplingMaterial.SetVector("_OffsetInfos", new Vector4(0.0f, verticalBlur, 0, 0)); + m_SamplingMaterial.SetVector("_Tint", tint); + m_SamplingMaterial.SetFloat("_Intensity", intensity); + Graphics.Blit(source, tmpTexture, m_SamplingMaterial, passFromSamples); + + Texture additiveColor = null; + if (additiveTexture == null) + additiveColor = Texture2D.blackTexture; + else + additiveColor = additiveTexture; + + // Horizontal + m_SamplingMaterial.SetTexture("_AdditiveTexture", additiveColor); + m_SamplingMaterial.SetVector("_OffsetInfos", new Vector4(horizontalBlur, 0.0f, 1.0f / destination.width, 1.0f / destination.height)); + m_SamplingMaterial.SetVector("_Tint", Color.white); + m_SamplingMaterial.SetFloat("_Intensity", 1.0f); + Graphics.Blit(tmpTexture, destination, m_SamplingMaterial, passFromSamples); + + RenderTexture.ReleaseTemporary(tmpTexture); + } + + void RenderTextureAdditive(RenderTexture source, RenderTexture destination, float intensity) + { + + RenderTexture tmpTexture = RenderTexture.GetTemporary(source.width, source.height, source.depth, source.format); + Graphics.Blit(destination, tmpTexture); + + m_MixerMaterial.SetTexture("_ColorBuffer", tmpTexture); + m_MixerMaterial.SetFloat("_Intensity", intensity); + + Graphics.Blit(source, destination, m_MixerMaterial, 0); + + RenderTexture.ReleaseTemporary(tmpTexture); + } + + void BlitIntensity(RenderTexture source, RenderTexture destination, float intensity) + { + m_MixerMaterial.SetFloat("_Intensity", intensity); + Graphics.Blit(source, destination, m_MixerMaterial, 2); + } + + void CombineAdditive(RenderTexture source, RenderTexture destination, float intensitySource, float intensityDestination) + { + RenderTexture tmpTexture = RenderTexture.GetTemporary(source.width, source.height, source.depth, source.format); + Graphics.Blit(destination, tmpTexture); + + m_MixerMaterial.SetTexture("_ColorBuffer", tmpTexture); + m_MixerMaterial.SetFloat("_Intensity0", intensitySource); + m_MixerMaterial.SetFloat("_Intensity1", intensityDestination); + Graphics.Blit(source, destination, m_MixerMaterial, 1); + + RenderTexture.ReleaseTemporary(tmpTexture); + } + + public void SetFilmicCurveParameters(float middle, float dark, float bright, float highlights) + { + m_BloomCurve.m_ToeStrength = -1.0f * dark; + m_BloomCurve.m_ShoulderStrength = bright; + m_BloomCurve.m_Highlights = highlights; + m_BloomCurve.m_CrossOverPoint = middle; + m_BloomCurve.UpdateCoefficients(); + } + + + + /* float Gaussian(float Scale, int iSamplePoint) + { + float sigma = (Scale - 1.0f) / 6.5f; + float g = 1.0f / Mathf.Sqrt(2.0f * 3.14159f * sigma * sigma); + return (g * Mathf.Exp(-(iSamplePoint * iSamplePoint) / (2 * sigma * sigma))); + } + + void Start() + { + int count = 16; + float scale = 31; + float sum = 0.0f; + float[] weights = new float[count]; + for (int i = 0; i < count; ++i) + { + weights[i] = Gaussian(scale, i); + sum += weights[i]; + } + + string str = ""; + for (int i = 0; i < count; ++i) + { + float nWeight = weights[i] / sum; + + if (i == 0) + { + str += "color += " + nWeight + " * tex2D (_MainTex, gUV);\n"; + } + else + { + str += "color += " + nWeight + " * tex2D (_MainTex, gUV + _OffsetInfos.xy * " + i + ");\n"; + str += "color += " + nWeight + " * tex2D (_MainTex, gUV - _OffsetInfos.xy * " + i + ");\n"; + } + //Debug.Log("" + i + ": " + nWeight); + } + + Debug.Log(str); + } + * */ +} + + diff --git a/Assets/Cinematic Effects/BloomBeta/Scripts/UltimateBloom.cs.meta b/Assets/Cinematic Effects/BloomBeta/Scripts/UltimateBloom.cs.meta new file mode 100644 index 0000000..6263d1b --- /dev/null +++ b/Assets/Cinematic Effects/BloomBeta/Scripts/UltimateBloom.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: c248faf0e10cd5a4cb2ca648c286bfa8 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/BloomBeta/UltimateBloomPathLocator.cs b/Assets/Cinematic Effects/BloomBeta/UltimateBloomPathLocator.cs new file mode 100644 index 0000000..78719e6 --- /dev/null +++ b/Assets/Cinematic Effects/BloomBeta/UltimateBloomPathLocator.cs @@ -0,0 +1,10 @@ +using UnityEngine; +using System.Collections; + +/// +/// Used to locate the root Ultimate Bloom Folder +/// +public class UltimateBloomPathLocator : ScriptableObject +{ + +} diff --git a/Assets/Cinematic Effects/BloomBeta/UltimateBloomPathLocator.cs.meta b/Assets/Cinematic Effects/BloomBeta/UltimateBloomPathLocator.cs.meta new file mode 100644 index 0000000..8c1f6b2 --- /dev/null +++ b/Assets/Cinematic Effects/BloomBeta/UltimateBloomPathLocator.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: f196cd8bdabf54842954784952e8d059 +timeCreated: 1456303354 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/Common.meta b/Assets/Cinematic Effects/Common.meta new file mode 100644 index 0000000..df0a642 --- /dev/null +++ b/Assets/Cinematic Effects/Common.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 88d2f1c604c7f6d4bb80a72b2f0219a7 +folderAsset: yes +timeCreated: 1449044555 +licenseType: Pro +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/Common/Editor.meta b/Assets/Cinematic Effects/Common/Editor.meta new file mode 100644 index 0000000..1acf785 --- /dev/null +++ b/Assets/Cinematic Effects/Common/Editor.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: e862ecde714eb154ca2d86a9a0809732 +folderAsset: yes +timeCreated: 1453372226 +licenseType: Pro +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/Common/Editor/EditorGUIHelper.cs b/Assets/Cinematic Effects/Common/Editor/EditorGUIHelper.cs new file mode 100644 index 0000000..05fb09a --- /dev/null +++ b/Assets/Cinematic 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/Assets/Cinematic Effects/Common/Editor/EditorGUIHelper.cs.meta b/Assets/Cinematic Effects/Common/Editor/EditorGUIHelper.cs.meta new file mode 100644 index 0000000..0bb1a64 --- /dev/null +++ b/Assets/Cinematic Effects/Common/Editor/EditorGUIHelper.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 5b995f06a3ed14d449823cf7ab1c5a58 +timeCreated: 1454681943 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/Common/Editor/FieldFinder.cs b/Assets/Cinematic Effects/Common/Editor/FieldFinder.cs new file mode 100644 index 0000000..fe77bdd --- /dev/null +++ b/Assets/Cinematic 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/Assets/Cinematic Effects/Common/Editor/FieldFinder.cs.meta b/Assets/Cinematic Effects/Common/Editor/FieldFinder.cs.meta new file mode 100644 index 0000000..6a4c16d --- /dev/null +++ b/Assets/Cinematic Effects/Common/Editor/FieldFinder.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 39e54cb37a3a81a40b248f1cc25c4619 +timeCreated: 1454073160 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/Common/Editor/MinDrawer.cs b/Assets/Cinematic Effects/Common/Editor/MinDrawer.cs new file mode 100644 index 0000000..73ca7b2 --- /dev/null +++ b/Assets/Cinematic 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/Assets/Cinematic Effects/Common/Editor/MinDrawer.cs.meta b/Assets/Cinematic Effects/Common/Editor/MinDrawer.cs.meta new file mode 100644 index 0000000..2e95f53 --- /dev/null +++ b/Assets/Cinematic Effects/Common/Editor/MinDrawer.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 9c615a85f13c6764fa4496d1d7f75f52 +timeCreated: 1453220014 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/Common/ImageEffectHelper.cs b/Assets/Cinematic Effects/Common/ImageEffectHelper.cs new file mode 100644 index 0000000..d3761b6 --- /dev/null +++ b/Assets/Cinematic 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/Assets/Cinematic Effects/Common/ImageEffectHelper.cs.meta b/Assets/Cinematic Effects/Common/ImageEffectHelper.cs.meta new file mode 100644 index 0000000..eb58b71 --- /dev/null +++ b/Assets/Cinematic Effects/Common/ImageEffectHelper.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: ab6a3f50deeee984c88794eeeb901226 +timeCreated: 1448544124 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/Common/MinAttribute.cs b/Assets/Cinematic Effects/Common/MinAttribute.cs new file mode 100644 index 0000000..84e7c1a --- /dev/null +++ b/Assets/Cinematic 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/Assets/Cinematic Effects/Common/MinAttribute.cs.meta b/Assets/Cinematic Effects/Common/MinAttribute.cs.meta new file mode 100644 index 0000000..8dcc710 --- /dev/null +++ b/Assets/Cinematic Effects/Common/MinAttribute.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: b07292ae638766047a6751da7552e566 +timeCreated: 1453220005 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/Common/RenderTextureUtility.cs b/Assets/Cinematic Effects/Common/RenderTextureUtility.cs new file mode 100644 index 0000000..ae71657 --- /dev/null +++ b/Assets/Cinematic 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/Assets/Cinematic Effects/Common/RenderTextureUtility.cs.meta b/Assets/Cinematic Effects/Common/RenderTextureUtility.cs.meta new file mode 100644 index 0000000..b866db1 --- /dev/null +++ b/Assets/Cinematic Effects/Common/RenderTextureUtility.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 054e694bae00c374a97c2bc495fca66b +timeCreated: 1449148391 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/DepthOfField.meta b/Assets/Cinematic Effects/DepthOfField.meta new file mode 100644 index 0000000..50072ec --- /dev/null +++ b/Assets/Cinematic Effects/DepthOfField.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 34369cdf66de04c65a8cef766bb1797b +folderAsset: yes +timeCreated: 1429220270 +licenseType: Pro +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/DepthOfField/DepthOfField.cs b/Assets/Cinematic Effects/DepthOfField/DepthOfField.cs new file mode 100644 index 0000000..ec469ec --- /dev/null +++ b/Assets/Cinematic Effects/DepthOfField/DepthOfField.cs @@ -0,0 +1,946 @@ +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 = 35.0f; + + #region Render passes + private enum Passes + { + BlurAlphaWeighted = 0 , + BoxBlur = 1 , + DilateFgCocFromColor = 2 , + DilateFgCoc = 3 , + CaptureCoc = 4 , + CaptureCocExplicit = 5 , + VisualizeCoc = 6 , + VisualizeCocExplicit = 7 , + CocPrefilter = 8 , + CircleBlur = 9 , + CircleBlurWithDilatedFg = 10, + CircleBlurLowQuality = 11, + CircleBlowLowQualityWithDilatedFg = 12, + Merge = 13, + MergeExplicit = 14, + MergeBicubic = 15, + MergeExplicitBicubic = 16, + ShapeLowQuality = 17, + ShapeLowQualityDilateFg = 18, + ShapeLowQualityMerge = 19, + ShapeLowQualityMergeDilateFg = 20, + ShapeMediumQuality = 21, + ShapeMediumQualityDilateFg = 22, + ShapeMediumQualityMerge = 23, + ShapeMediumQualityMergeDilateFg = 24, + ShapeHighQuality = 25, + ShapeHighQualityDilateFg = 26, + ShapeHighQualityMerge = 27, + ShapeHighQualityMergeDilateFg = 28 + } + + private enum MedianPasses + { + Median3 = 0, + Median3X3 = 1 + } + + private enum BokehTexturesPasses + { + Apply = 0, + Collect = 1 + } + #endregion + + public enum TweakMode + { + Basic, + Advanced, + Explicit + } + + public enum ApertureShape + { + Circular, + Hexagonal, + Octogonal + } + + public enum QualityPreset + { + Simple, + Low, + Medium, + High, + VeryHigh, + Ultra, + Custom + } + + public enum FilterQuality + { + None, + Normal, + High + } + + #region Attributes + [AttributeUsage(AttributeTargets.Field)] + public class TopLevelSettings : Attribute + {} + + [AttributeUsage(AttributeTargets.Field)] + public class SettingsGroup : Attribute + {} + + [AttributeUsage(AttributeTargets.Field)] + public class AllTweakModes : Attribute + {} + + [AttributeUsage(AttributeTargets.Field)] + public class Basic : Attribute + {} + + [AttributeUsage(AttributeTargets.Field)] + public class Advanced : Attribute + {} + + [AttributeUsage(AttributeTargets.Field)] + public class Explicit : Attribute + {} + #endregion + + #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 visualizeBluriness; + + [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 quality; + + [Space, 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 + { + visualizeBluriness = false, + tweakMode = TweakMode.Basic, + quality = 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; + + [Tooltip("Uses high quality upsampling.")] + public bool highQualityUpsampling; + + [Tooltip("Prevent haloing from bright in focus region over dark out of focus region.")] + public bool preventHaloing; + + public static QualitySettings[] presetQualitySettings = + { + // Simple + new QualitySettings + { + prefilterBlur = false, + medianFilter = FilterQuality.None, + dilateNearBlur = false, + highQualityUpsampling = false, + preventHaloing = false + }, + + // Low + new QualitySettings + { + prefilterBlur = true, + medianFilter = FilterQuality.None, + dilateNearBlur = false, + highQualityUpsampling = false, + preventHaloing = false + }, + + // Medium + new QualitySettings + { + prefilterBlur = true, + medianFilter = FilterQuality.Normal, + dilateNearBlur = false, + highQualityUpsampling = false, + preventHaloing = false + }, + + // High + new QualitySettings + { + prefilterBlur = true, + medianFilter = FilterQuality.Normal, + dilateNearBlur = true, + highQualityUpsampling = false, + preventHaloing = false + }, + + // Very high + new QualitySettings + { + prefilterBlur = true, + medianFilter = FilterQuality.High, + dilateNearBlur = true, + highQualityUpsampling = false, + preventHaloing = true + }, + + // Ultra + new QualitySettings + { + prefilterBlur = true, + medianFilter = FilterQuality.High, + dilateNearBlur = true, + highQualityUpsampling = true, + preventHaloing = true + } + }; + } + + [Serializable] + public struct FocusSettings + { + [Basic, Advanced, Explicit, Tooltip("Auto-focus on a selected transform.")] + public Transform transform; + + [Basic, Advanced, Explicit, Range(0f, 1f), Tooltip("Focus distance.")] + public float plane; + + [Explicit, Range(0f, 1f), Tooltip("Near focus distance.")] + public float nearPlane; + + [Explicit, Range(0f, 1f), Tooltip("Far focus distance.")] + public float farPlane; + + [Basic, Advanced, Range(0f, 32f), Tooltip("Simulates focal ratio. Lower values will result in a narrow depth of field.")] + public float fStops; + + [Basic, Advanced, Explicit, Range(0f, 1f), Tooltip("Focus range/spread. Use this to fine-tune the F-Stop range.")] + public float rangeAdjustment; + + public static FocusSettings defaultSettings + { + get + { + return new FocusSettings + { + transform = null, + plane = 0.225f, + nearPlane = 0f, + farPlane = 1f, + fStops = 5f, + rangeAdjustment = 0.9f + }; + } + } + } + + [Serializable] + public struct BokehTextureSettings + { + [Advanced, Explicit, 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; + + [Advanced, Explicit, Range(0.01f, 5f), Tooltip("Maximum size of bokeh textures on screen.")] + public float scale; + + [Advanced, Explicit, Range(0.01f, 100f), Tooltip("Bokeh brightness.")] + public float intensity; + + [Advanced, Explicit, Range(0.01f, 50f), Tooltip("Controls the amount of bokeh textures. Lower values mean more bokeh splats.")] + public float threshold; + + [Advanced, Explicit, 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 + }; + } + } + } + + [Serializable] + public struct BlurSettings + { + [Basic, Advanced, Explicit, Range(0f, kMaxBlur), Tooltip("Maximum blur radius for the near plane.")] + public float nearRadius; + + [Basic, Advanced, Explicit, Range(0f, kMaxBlur), Tooltip("Maximum blur radius for the far plane.")] + public float farRadius; + + [Advanced, Explicit, Range(0.5f, 4f), Tooltip("Blur luminosity booster threshold for the near and far boost amounts.")] + public float boostPoint; + + [Advanced, Explicit, Range(0f, 1f), Tooltip("Boosts luminosity in the near blur.")] + public float nearBoostAmount; + + [Advanced, Explicit, Range(0f, 1f), Tooltip("Boosts luminosity in the far blur.")] + public float farBoostAmount; + + public static BlurSettings defaultSettings + { + get + { + return new BlurSettings + { + nearRadius = 20f, + farRadius = 20f, + boostPoint = 0.75f, + nearBoostAmount = 0f, + farBoostAmount = 0f, + }; + } + } + } + #endregion + + [TopLevelSettings] + public GlobalSettings settings = GlobalSettings.defaultSettings; + + [SettingsGroup, AllTweakModes] + public QualitySettings quality = QualitySettings.presetQualitySettings[3]; + + [SettingsGroup] + public FocusSettings focus = FocusSettings.defaultSettings; + + [SettingsGroup] + public BokehTextureSettings bokehTexture = BokehTextureSettings.defaultSettings; + + [SettingsGroup] + public BlurSettings blur = BlurSettings.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_0 || UNITY_5_1 || UNITY_5_2 || UNITY_5_3) + m_ComputeBufferDrawArgs = new ComputeBuffer(1, 16, ComputeBufferType.DrawIndirect); +#else + m_ComputeBufferDrawArgs = new ComputeBuffer(1, 16, ComputeBufferType.IndirectArguments); +#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.visualizeBluriness) + { + Vector4 blurrinessParam; + Vector4 blurrinessCoe; + ComputeCocParameters(out blurrinessParam, out blurrinessCoe); + filmicDepthOfFieldMaterial.SetVector("_BlurParams", blurrinessParam); + filmicDepthOfFieldMaterial.SetVector("_BlurCoe", blurrinessCoe); + Graphics.Blit(null, destination, filmicDepthOfFieldMaterial, (settings.tweakMode == TweakMode.Explicit) ? (int)Passes.VisualizeCocExplicit : (int)Passes.VisualizeCoc); + } + else + { + DoDepthOfField(source, destination); + } + + m_RTU.ReleaseAllTemporaryRenderTextures(); + } + + private void DoDepthOfField(RenderTexture source, RenderTexture destination) + { + m_CurrentQualitySettings = quality; + + if (settings.quality != QualityPreset.Custom) + m_CurrentQualitySettings = QualitySettings.presetQualitySettings[(int)settings.quality]; + + float radiusAdjustement = source.height / 720.0f; + + float textureBokehScale = radiusAdjustement; + float textureBokehMaxRadius = Mathf.Max(blur.nearRadius, blur.farRadius) * textureBokehScale * 0.75f; + + float nearBlurRadius = blur.nearRadius * radiusAdjustement; + float farBlurRadius = blur.farRadius * 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; + Vector4 blurrinessCoe = new Vector4(nearBlurRadius * 0.5f, farBlurRadius * 0.5f, 0.0f, 0.0f); + RenderTexture colorAndCoc = m_RTU.GetTemporaryRenderTexture(rtW, rtH); + RenderTexture colorAndCoc2 = m_RTU.GetTemporaryRenderTexture(rtW, rtH); + + if (m_CurrentQualitySettings.preventHaloing) + filmicDepthOfFieldMaterial.EnableKeyword("USE_SPECIAL_FETCH_FOR_COC"); + else + filmicDepthOfFieldMaterial.DisableKeyword("USE_SPECIAL_FETCH_FOR_COC"); + + // Downsample to Color + COC buffer and apply boost + Vector4 cocParam; + Vector4 cocCoe; + ComputeCocParameters(out cocParam, out cocCoe); + filmicDepthOfFieldMaterial.SetVector("_BlurParams", cocParam); + filmicDepthOfFieldMaterial.SetVector("_BlurCoe", cocCoe); + filmicDepthOfFieldMaterial.SetVector("_BoostParams", new Vector4(nearBlurRadius * blur.nearBoostAmount * -0.5f, farBlurRadius * blur.farBoostAmount * 0.5f, blur.boostPoint, 0.0f)); + Graphics.Blit(source, colorAndCoc2, filmicDepthOfFieldMaterial, (settings.tweakMode == TweakMode.Explicit) ? (int)Passes.CaptureCocExplicit : (int)Passes.CaptureCoc); + RenderTexture src = colorAndCoc2; + RenderTexture dst = colorAndCoc; + + // Collect texture bokeh candidates and replace with a darker pixel + if (shouldPerformBokeh) + { + // Blur a bit so we can do a frequency check + RenderTexture blurred = m_RTU.GetTemporaryRenderTexture(rtW, rtH); + Graphics.Blit(src, blurred, filmicDepthOfFieldMaterial, (int)Passes.BoxBlur); + filmicDepthOfFieldMaterial.SetVector("_Offsets", new Vector4(0.0f, 1.5f, 0.0f, 1.5f)); + Graphics.Blit(blurred, dst, filmicDepthOfFieldMaterial, (int)Passes.BlurAlphaWeighted); + filmicDepthOfFieldMaterial.SetVector("_Offsets", new Vector4(1.5f, 0.0f, 0.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); + filmicDepthOfFieldMaterial.SetVector("_BoostParams", new Vector4(nearBlurRadius * blur.nearBoostAmount * -0.5f, farBlurRadius * blur.farBoostAmount * 0.5f, blur.boostPoint, 0.0f)); + + // Dilate near blur factor + RenderTexture blurredFgCoc = null; + if (m_CurrentQualitySettings.dilateNearBlur) + { + RenderTexture blurredFgCoc2 = m_RTU.GetTemporaryRenderTexture(rtW, rtH, 0, RenderTextureFormat.RGHalf); + blurredFgCoc = m_RTU.GetTemporaryRenderTexture(rtW, rtH, 0, RenderTextureFormat.RGHalf); + filmicDepthOfFieldMaterial.SetVector("_Offsets", new Vector4(0.0f, nearBlurRadius * 0.75f, 0.0f, 0.0f)); + Graphics.Blit(src, blurredFgCoc2, filmicDepthOfFieldMaterial, (int)Passes.DilateFgCocFromColor); + filmicDepthOfFieldMaterial.SetVector("_Offsets", new Vector4(nearBlurRadius * 0.75f, 0.0f, 0.0f, 0.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(1.0f, 0.0f, 0.0f, 0.0f)); + Graphics.Blit(src, dst, medianFilterMaterial, (int)MedianPasses.Median3); + SwapRenderTexture(ref src, ref dst); + medianFilterMaterial.SetVector("_Offsets", new Vector4(0.0f, 1.0f, 0.0f, 0.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, 1.0f / src.width, 1.0f / src.height)); + filmicDepthOfFieldMaterial.SetTexture("_SecondTex", src); + int mergePass = (settings.tweakMode == TweakMode.Explicit) ? (int)Passes.MergeExplicit : (int)Passes.Merge; + if (m_CurrentQualitySettings.highQualityUpsampling) + mergePass = (settings.tweakMode == TweakMode.Explicit) ? (int)Passes.MergeExplicitBicubic : (int)Passes.MergeBicubic; + + // Apply texture bokeh + if (shouldPerformBokeh) + { + RenderTexture 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(1.0f / (1.0f * source.width), 1.0f / (1.0f * 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); + RenderTexture 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); + RenderTexture 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 > 10.0f) ? (int)Passes.CircleBlurWithDilatedFg : (int)Passes.CircleBlowLowQualityWithDilatedFg; + } + else + { + bokehPass = (maxRadius > 10.0f) ? (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) + { + Camera sceneCamera = GetComponent(); + float focusDistance01 = focus.transform + ? (sceneCamera.WorldToViewportPoint(focus.transform.position)).z / (sceneCamera.farClipPlane) + : (focus.plane * focus.plane * focus.plane * focus.plane); + + if (settings.tweakMode == TweakMode.Basic || settings.tweakMode == TweakMode.Advanced) + { + float focusRange01 = focus.rangeAdjustment * focus.rangeAdjustment * focus.rangeAdjustment * focus.rangeAdjustment; + float focalLength = 4.0f / Mathf.Tan(0.5f * sceneCamera.fieldOfView * Mathf.Deg2Rad); + float aperture = focalLength / focus.fStops; + blurCoe = new Vector4(0.0f, 0.0f, 1.0f, 1.0f); + blurParams = new Vector4(aperture, focalLength, focusDistance01, focusRange01); + } + else + { + float nearDistance01 = focus.nearPlane * focus.nearPlane * focus.nearPlane * focus.nearPlane; + float farDistance01 = focus.farPlane * focus.farPlane * focus.farPlane * focus.farPlane; + float nearFocusRange01 = focus.rangeAdjustment * focus.rangeAdjustment * focus.rangeAdjustment * focus.rangeAdjustment; + float farFocusRange01 = nearFocusRange01; + + if (focusDistance01 <= nearDistance01) + focusDistance01 = nearDistance01 + 0.0000001f; + if (focusDistance01 >= farDistance01) + focusDistance01 = farDistance01 - 0.0000001f; + if ((focusDistance01 - nearFocusRange01) <= nearDistance01) + nearFocusRange01 = (focusDistance01 - nearDistance01 - 0.0000001f); + if ((focusDistance01 + farFocusRange01) >= farDistance01) + farFocusRange01 = (farDistance01 - focusDistance01 - 0.0000001f); + + float a1 = 1.0f / (nearDistance01 - focusDistance01 + nearFocusRange01); + float a2 = 1.0f / (farDistance01 - focusDistance01 - farFocusRange01); + float b1 = (1.0f - a1 * nearDistance01), b2 = (1.0f - a2 * farDistance01); + const float c1 = -1.0f; + const float c2 = 1.0f; + blurParams = new Vector4(c1 * a1, c1 * b1, c2 * a2, c2 * b2); + blurCoe = new Vector4(0.0f, 0.0f, (b2 - b1) / (a1 - a2), 0.0f); + } + } + + 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, 0.0f, 0.0f, 0.0f); + m_OctogonalBokehDirection2 = new Vector4(0.0f, 0.5f, 1.0f, 0.0f); + m_OctogonalBokehDirection3 = new Vector4(-0.353553f, 0.353553f, 1.0f, 0.0f); + m_OctogonalBokehDirection4 = new Vector4(0.353553f, 0.353553f, 1.0f, 0.0f); + + m_HexagonalBokehDirection1 = new Vector4(0.5f, 0.0f, 0.0f, 0.0f); + m_HexagonalBokehDirection2 = new Vector4(0.25f, 0.433013f, 1.0f, 0.0f); + m_HexagonalBokehDirection3 = new Vector4(0.25f, -0.433013f, 1.0f, 0.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 && settings.tweakMode != TweakMode.Basic; } + } + + private static void Rotate2D(ref Vector4 direction, float cosinus, float sinus) + { + Vector4 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 > 10.0f) + { + blurPass = (int)Passes.ShapeHighQuality; + blurAndMergePass = (int)Passes.ShapeHighQualityMerge; + } + else if (maxRadius > 5.0f) + { + blurPass = (int)Passes.ShapeMediumQuality; + blurAndMergePass = (int)Passes.ShapeMediumQualityMerge; + } + else + { + blurPass = (int)Passes.ShapeLowQuality; + blurAndMergePass = (int)Passes.ShapeLowQualityMerge; + } + } + else + { + if (maxRadius > 10.0f) + { + blurPass = (int)Passes.ShapeHighQualityDilateFg; + blurAndMergePass = (int)Passes.ShapeHighQualityMergeDilateFg; + } + else if (maxRadius > 5.0f) + { + blurPass = (int)Passes.ShapeMediumQualityDilateFg; + blurAndMergePass = (int)Passes.ShapeMediumQualityMergeDilateFg; + } + else + { + blurPass = (int)Passes.ShapeLowQualityDilateFg; + blurAndMergePass = (int)Passes.ShapeLowQualityMergeDilateFg; + } + } + } + } +} diff --git a/Assets/Cinematic Effects/DepthOfField/DepthOfField.cs.meta b/Assets/Cinematic Effects/DepthOfField/DepthOfField.cs.meta new file mode 100644 index 0000000..9216b06 --- /dev/null +++ b/Assets/Cinematic Effects/DepthOfField/DepthOfField.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 8a338d679868f45439ea43c7ae035e36 +timeCreated: 1453985420 +licenseType: Pro +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/Assets/Cinematic Effects/DepthOfField/Editor.meta b/Assets/Cinematic Effects/DepthOfField/Editor.meta new file mode 100644 index 0000000..e10867b --- /dev/null +++ b/Assets/Cinematic Effects/DepthOfField/Editor.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 1a8273952ce5743428d8c42b25cb0458 +folderAsset: yes +timeCreated: 1449046242 +licenseType: Pro +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/DepthOfField/Editor/DepthOfFieldEditor.cs b/Assets/Cinematic Effects/DepthOfField/Editor/DepthOfFieldEditor.cs new file mode 100644 index 0000000..9c35a4d --- /dev/null +++ b/Assets/Cinematic Effects/DepthOfField/Editor/DepthOfFieldEditor.cs @@ -0,0 +1,109 @@ +using UnityEditor; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; + +namespace UnityStandardAssets.CinematicEffects +{ + [CustomEditor(typeof(DepthOfField))] + class DepthOfFieldEditor : Editor + { + private List m_TopLevelFields = new List(); + private Dictionary> m_GroupFields = new Dictionary>(); + private Dictionary> m_AccessFields = new Dictionary>(); + + private DepthOfField.TweakMode tweakMode + { + get { return ((DepthOfField)target).settings.tweakMode; } + } + + private void OnEnable() + { + var topLevelSettings = typeof(DepthOfField).GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance).Where(x => x.GetCustomAttributes(typeof(DepthOfField.TopLevelSettings), false).Any()); + var settingsGroups = typeof(DepthOfField).GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance).Where(x => x.GetCustomAttributes(typeof(DepthOfField.SettingsGroup), false).Any()); + + foreach (var group in topLevelSettings) + { + var searchPath = 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); + } + } + + var basicFields = new List(); + var advancedFields = new List(); + var explicitFields = new List(); + + foreach (var group in settingsGroups) + { + 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); + if (setting.GetCustomAttributes(typeof(DepthOfField.Basic), false).Length > 0) + basicFields.Add(property); + if (setting.GetCustomAttributes(typeof(DepthOfField.Advanced), false).Length > 0) + advancedFields.Add(property); + if (setting.GetCustomAttributes(typeof(DepthOfField.Explicit), false).Length > 0) + explicitFields.Add(property); + } + } + } + + m_AccessFields[DepthOfField.TweakMode.Basic] = basicFields; + m_AccessFields[DepthOfField.TweakMode.Advanced] = advancedFields; + m_AccessFields[DepthOfField.TweakMode.Explicit] = explicitFields; + } + + public override void OnInspectorGUI() + { + serializedObject.Update(); + + foreach (var setting in m_TopLevelFields) + EditorGUILayout.PropertyField(setting); + + List accessList = m_AccessFields[tweakMode]; + + foreach (var group in m_GroupFields) + { + if (group.Key.FieldType == typeof(DepthOfField.QualitySettings) && ((DepthOfField)target).settings.quality != DepthOfField.QualityPreset.Custom) + continue; + + bool forceInclude = group.Key.GetCustomAttributes(typeof(DepthOfField.AllTweakModes), false).Length > 0; + + int count = group.Value.Count(x => accessList.Contains(x)); + if (!forceInclude && count == 0) + continue; + + EditorGUILayout.Space(); + EditorGUILayout.LabelField(ObjectNames.NicifyVariableName(group.Key.Name), EditorStyles.boldLabel); + EditorGUI.indentLevel++; + + foreach (var field in group.Value) + { + if (forceInclude || accessList.Contains(field)) + EditorGUILayout.PropertyField(field); + } + + EditorGUI.indentLevel--; + } + + serializedObject.ApplyModifiedProperties(); + } + } +} diff --git a/Assets/Cinematic Effects/DepthOfField/Editor/DepthOfFieldEditor.cs.meta b/Assets/Cinematic Effects/DepthOfField/Editor/DepthOfFieldEditor.cs.meta new file mode 100644 index 0000000..5ccd63d --- /dev/null +++ b/Assets/Cinematic Effects/DepthOfField/Editor/DepthOfFieldEditor.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 3eb07ef5681934662814cc768bcdb60c +timeCreated: 1429220270 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/DepthOfField/Helpers.meta b/Assets/Cinematic Effects/DepthOfField/Helpers.meta new file mode 100644 index 0000000..59bf0ab --- /dev/null +++ b/Assets/Cinematic Effects/DepthOfField/Helpers.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 5427d9a5126366c42b9509de8233bff7 +folderAsset: yes +timeCreated: 1453985653 +licenseType: Pro +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/DepthOfField/Helpers/HexShape.psd b/Assets/Cinematic 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/Assets/Cinematic Effects/DepthOfField/Helpers/HexShape.psd.meta b/Assets/Cinematic Effects/DepthOfField/Helpers/HexShape.psd.meta new file mode 100644 index 0000000..213b2ae --- /dev/null +++ b/Assets/Cinematic Effects/DepthOfField/Helpers/HexShape.psd.meta @@ -0,0 +1,55 @@ +fileFormatVersion: 2 +guid: 904882c15ff3d4122a99f80ff4f23741 +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/Assets/Cinematic Effects/DepthOfField/Helpers/RoundedHexShape.tif b/Assets/Cinematic 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/Assets/Cinematic Effects/DepthOfField/Helpers/RoundedHexShape.tif.meta b/Assets/Cinematic Effects/DepthOfField/Helpers/RoundedHexShape.tif.meta new file mode 100644 index 0000000..ce68835 --- /dev/null +++ b/Assets/Cinematic Effects/DepthOfField/Helpers/RoundedHexShape.tif.meta @@ -0,0 +1,57 @@ +fileFormatVersion: 2 +guid: 9014ef007a9a1d545b0fba20daa0fc7c +timeCreated: 1454425451 +licenseType: Pro +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/Assets/Cinematic Effects/DepthOfField/Helpers/SphereShape.psd b/Assets/Cinematic 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) return BOKEH_ZERO_VEC; + if(uv.y<=0) return BOKEH_ZERO_VEC; if(uv.y>=1) 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, 1); + o.color = pointBuffer[id].color; + #if UNITY_UV_STARTS_AT_TOP + o.pos.y *= -1; + #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) + o.uv_flip.y = 1.0-o.uv_flip.y; + if(_MainTex_TexelSize.y<0) + 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; + offs.xy = float2(3.0, 3.0) + 2.0f * floor(scale2 + float2(0.5,0.5)); + + float2 rs = ((float2(1.0, 1.0) + 2.0f * (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,1,0,0); + output.misc = float4(f2,0,0); + output.uv = float3(0, 1, input[0].cocOverlap); + output.color = input[0].color * energyAdjustment; + outStream.Append (output); + + output.pos = input[0].pos + offs*float4(1,1,0,0); + output.misc = float4(f2,0,0); + output.uv = float3(1, 1, input[0].cocOverlap); + output.color = input[0].color * energyAdjustment; + outStream.Append (output); + + output.pos = input[0].pos + offs*float4(-1,-1,0,0); + output.misc = float4(f2,0,0); + output.uv = float3(0, 0, input[0].cocOverlap); + output.color = input[0].color * energyAdjustment; + outStream.Append (output); + + output.pos = input[0].pos + offs*float4(1,-1,0,0); + output.misc = float4(f2,0,0); + output.uv = float3(1, 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.0h); + + [branch] + if (coc * _BokehParams.w > 1 && 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), coc); + pointBufferOutput.Append(append); + c = half4(c.rgb * saturate(1-coc*4), 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/Assets/Cinematic Effects/DepthOfField/Resources/BokehSplatting.shader.meta b/Assets/Cinematic Effects/DepthOfField/Resources/BokehSplatting.shader.meta new file mode 100644 index 0000000..b36b645 --- /dev/null +++ b/Assets/Cinematic Effects/DepthOfField/Resources/BokehSplatting.shader.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: c961b8ed1f00f924d804ada5143bd0e8 +timeCreated: 1449750679 +licenseType: Pro +ShaderImporter: + defaultTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/DepthOfField/Resources/DepthOfField.shader b/Assets/Cinematic Effects/DepthOfField/Resources/DepthOfField.shader new file mode 100644 index 0000000..a049886 --- /dev/null +++ b/Assets/Cinematic Effects/DepthOfField/Resources/DepthOfField.shader @@ -0,0 +1,1447 @@ +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 _BoostParams; +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) + o.uv.y = 1-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) + o.uv.y = 1-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) + o.uv.y = 1-o.uv.y; + if (_MainTex_TexelSize.y < 0) + o.uv1.y = 1-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); +#else + return tex2Dlod (_MainTex, float4(uv,0,0)); +#endif +} + +inline half2 GetBilinearFetchTexOffsetFromAbsCoc(half4 absCoc) +{ + half4 cocWeights = absCoc * absCoc * absCoc; + + half2 offset = 0; + offset += cocWeights.r * float2(-1,+1); + offset += cocWeights.g * float2(+1,+1); + offset += cocWeights.b * float2(+1,-1); + offset += cocWeights.a * float2(-1,-1); + offset = clamp((half2)-1,(half2)1, 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_SPECIAL_FETCH_FOR_COC) + + #if defined(USE_TEX2DOBJECT_FOR_COC) + half4 allCoc = _MainTex.GatherAlpha(sampler_MainTex, uv); + half cocAB = (abs(allCoc.r) 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)).a; + #endif + + fetch.a = coc; +#endif + return fetch; +} + +inline half3 getBoostAmount(half4 colorAndCoc) +{ + half boost = colorAndCoc.a * (colorAndCoc.a < 0.0f ?_BoostParams.x:_BoostParams.y); + half luma = dot(colorAndCoc.rgb, half3(0.3h, 0.59h, 0.11h)); + return luma < _BoostParams.z ? half3(0.0h, 0.0h, 0.0h):colorAndCoc.rgb * boost.rrr; +} + +inline half GetCocFromZValue(half d, bool useExplicit) +{ + d = Linear01Depth (d); + + if (useExplicit) + { + half coc = d < _BlurCoe.z ? clamp((_BlurParams.x * d + _BlurParams.y), -1.0f, 0.0f):clamp((_BlurParams.z * d + _BlurParams.w), 0.0f, 1.0f); + return coc; + } + else + { + half aperture = _BlurParams.x; + half focalLength = _BlurParams.y; + half focusDistance01 = _BlurParams.z; + half focusRange01 = _BlurParams.w; + half coc = aperture * abs(d - focusDistance01) / (d + 1e-5f) - focusRange01; + coc = (d < focusDistance01 ? -1.0h:1.0h) * clamp(coc, 0.0f, 1.0f); + return coc; + } +} + +inline half GetCocFromDepth(half2 uv, bool useExplicit) +{ +#if defined(USE_TEX2DOBJECT_FOR_COC) + half d = _CameraDepthTexture.SampleLevel(sampler_CameraDepthTexture, uv, 0); +#else + half d = SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, uv); +#endif + return GetCocFromZValue(d,useExplicit); +} + +#if (SHADER_TARGET < 50 && !defined(SHADER_API_PSSL)) + half rcp(half x) { return 1 / 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*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*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)).rg; + fgCoc = min(cocs.r, cocs.g); + centerTap.a = cocs.g; + } + + half bgRadius = smoothstep(0.0h, 0.85h, centerTap.a) * _BlurCoe.y; + half fgRadius = smoothstep(0.0h, 0.85h, -fgCoc) * _BlurCoe.x; + half radius = max(bgRadius, fgRadius); + if (radius < 1e-2f ) + { + return half4(centerTap.rgb, (sampleDilatedFG||mergePass)?fgBlendFromPreviousPass:centerTap.a); + } + + half radOtherFgRad = radius/(fgRadius + 1e-2h); + half radOtherBgRad = radius/(bgRadius + 1e-2h); + half2 range = radius * _MainTex_TexelSize.xy; + + half fgWeight = 0.001h; + half bgWeight = 0.001h; + half3 fgSum = half3(0,0,0); + half3 bgSum = half3(0,0,0); + + for (int k = 0; k < numSample; k++) + { + half t = (half)k / half(numSample-1); + 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)).g; + } + + half dist = abs(2.0h * t - 1); + half distanceFactor = saturate(-0.5f * abs(sample0.a - centerTap.a) * dist + 1.0f); + half isNear = max(0.0h, -sample0.a); + half isFar = max(0.0h, sample0.a) * distanceFactor; + isNear *= 1- smoothstep(1.0h, 2.0h, dist * radOtherFgRad); + isFar *= 1- smoothstep(1.0h, 2.0h, dist * radOtherBgRad); + + fgWeight += isNear; + fgSum += sample0.rgb * isNear; + bgWeight += isFar; + bgSum += sample0.rgb * isFar; + } + + half3 fgColor = fgSum / (fgWeight + 0.0001h); + half3 bgColor = bgSum / (bgWeight + 0.0001h); + half bgBlend = saturate (2.0h * bgWeight / numSample); + half fgBlend = saturate (2.0h * fgWeight / numSample); + + half3 finalBg = lerp(centerTap.rgb, bgColor, bgBlend); + half3 finalColor = lerp(finalBg, fgColor, max(max(0.0h , -centerTap.a) , fgBlend)); + + if (mergePass) + { + finalColor = min(finalColor, tex2Dlod(_ThirdTex, half4(uv,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)).r, fgCoc); + } + + half bgRadius = 0.5h * smoothstep(0.0h, 0.85h, centerTap.a) * _BlurCoe.y; + half fgRadius = 0.5h * smoothstep(0.0h, 0.85h, -fgCoc) * _BlurCoe.x; + half radius = max(bgRadius, fgRadius); + if (radius < 1e-2f ) + { + return half4(centerTap.rgb, 0); + } + + half2 poissonScale = radius * _MainTex_TexelSize.xy; + half fgWeight = max(0,-centerTap.a); + half bgWeight = max(0, centerTap.a); + half3 fgSum = centerTap.rgb * fgWeight; + half3 bgSum = centerTap.rgb * bgWeight; + + half radOtherFgRad = radius/(fgRadius + 1e-2h); + half radOtherBgRad = radius/(bgRadius + 1e-2h); + + 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.0h, -sample0.a); + half distanceFactor = saturate(-0.5f * abs(sample0.a - centerTap.a) * DiscBokeh48[l].z + 1.0f); + half isFar = max(0.0h, sample0.a) * distanceFactor; + isNear *= 1- smoothstep(1.0h, 2.0h, DiscBokeh48[l].z * radOtherFgRad); + isFar *= 1- smoothstep(1.0h, 2.0h, DiscBokeh48[l].z * radOtherBgRad); + + fgWeight += isNear; + fgSum += sample0.rgb * isNear; + bgWeight += isFar; + bgSum += sample0.rgb * isFar; + } + + half3 fgColor = fgSum / (fgWeight + 0.0001h); + half3 bgColor = bgSum / (bgWeight + 0.0001h); + half bgBlend = saturate (2.0h * bgWeight / 49.0h); + half fgBlend = saturate (2.0h * fgWeight / 49.0h); + + half3 finalBg = lerp(centerTap.rgb, bgColor, bgBlend); + half3 finalColor = lerp(finalBg, fgColor, max(max(0.0h , -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.01288369f, 0.5416069f), + half2(-0.9192798f, -0.09529364f), + half2(0.7596578f, 0.1922738f), + half2(-0.14132f, -0.2880242f), + half2(-0.5249333f, 0.7777638f), + half2(-0.5871695f, -0.7403569f), + half2(0.3202196f, -0.6442268f), + half2(0.8553214f, -0.3920982f), + half2(0.5827708f, 0.7599297f) +}; + +half4 fragCocPrefilter (v2fDepth i) : SV_Target +{ + half4 centerTap = FetchMainTex(i.uv); + half radius = 0.33h * 0.5h * (centerTap.a < 0.0f ? -(centerTap.a * _BlurCoe.x):(centerTap.a * _BlurCoe.y)); + half2 poissonScale = radius * _MainTex_TexelSize.xy; + + if (radius < 0.01h ) + { + return centerTap; + } + + half sampleCount = 1; + half3 sum = centerTap.rgb * 1; + 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.0h); + sum += sample0.rgb * weight; + sampleCount += weight; + } + + half4 returnValue = half4(sum / sampleCount, centerTap.a); + return returnValue; +} + +/////////////////////////////////////////////////////////////////////////////// +// Final merge and upsample +/////////////////////////////////////////////////////////////////////////////// + +inline half4 upSampleConvolved(half2 uv, bool useBicubic, bool useExplicit) +{ + half2 convolvedTexelPos = uv * _Convolved_TexelSize.xy; + half2 convolvedTexelCenter = floor( convolvedTexelPos ) + 0.5; + half2 convolvedTexelOffsetFromCenter = convolvedTexelPos - convolvedTexelCenter; + half2 offsetFromCoc = 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, useExplicit); + coc.g = GetCocFromZValue(coc.g, useExplicit); + coc.b = GetCocFromZValue(coc.b, useExplicit); + coc.a = GetCocFromZValue(coc.a, useExplicit); + + half4 absCoc = abs(coc); + offsetFromCoc = GetBilinearFetchTexOffsetFromAbsCoc(absCoc) * 0.5; + uv += offsetFromCoc * _Convolved_TexelSize.zw; +#endif + + if (useBicubic) + { + //bicubic upsampling (B-spline) + //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.166h * f3 + 0.5h * f2 - 0.5h * f + 0.166h; + half2 w1 = 0.5h * f3 - f2 + 0.666h; + half2 w3 = 0.166h * f3; + half2 w2 = 1.0h - 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.0h + f0); + half2 t1 = _Convolved_TexelSize.zw * (convolvedTexelCenter + 1.0h + f1); + + return tex2Dlod(_SecondTex, half4(t0.x, t0.y, 0, 0)) * s0.x * s0.y + + tex2Dlod(_SecondTex, half4(t1.x, t0.y, 0, 0)) * s1.x * s0.y + + tex2Dlod(_SecondTex, half4(t0.x, t1.y, 0, 0)) * s0.x * s1.y + + tex2Dlod(_SecondTex, half4(t1.x, t1.y, 0, 0)) * s1.x * s1.y; + } + else + { + return tex2Dlod(_SecondTex, half4(uv,0,0)); + } +} + +inline half4 dofMerge (half2 uv, bool useExplicit, bool useBicubic) +{ + half4 convolvedTap = upSampleConvolved(uv, useBicubic, useExplicit); + convolvedTap.rgb = ToneMapInvert(convolvedTap.rgb); + + half4 sourceTap = FetchMainTex(uv); + half coc = GetCocFromDepth(uv, useExplicit); + + sourceTap.rgb += getBoostAmount(half4(sourceTap.rgb, coc)); + + coc = (coc * _BlurCoe.y > 1.0h )?coc:0.0h; + half blendValue = smoothstep(0.0, 0.33h, max(coc, convolvedTap.a)); + half3 returnValue = lerp(sourceTap.rgb, convolvedTap.rgb, blendValue); + return (blendValue < 1e-2f) ? sourceTap : half4(returnValue.rgb, sourceTap.a); +} + +half4 fragMergeBicubic (v2fDepth i) : SV_Target +{ + return dofMerge(i.uv, false, true); +} + +half4 fragMergeExplicitBicubic (v2fDepth i) : SV_Target +{ + return dofMerge(i.uv, true, true); +} + +half4 fragMerge (v2fDepth i) : SV_Target +{ + return dofMerge(i.uv, false, false); +} + +half4 fragMergeExplicit (v2fDepth i) : SV_Target +{ + return dofMerge(i.uv, true, false); +} + +/////////////////////////////////////////////////////////////////////////////// +// Downsampling and COC computation +/////////////////////////////////////////////////////////////////////////////// + +inline half4 captureCoc(half2 uvColor, half2 uvDepth, bool useExplicit) +{ + /*****************/ + /* 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, useExplicit); + coc.g = GetCocFromZValue(coc.g, useExplicit); + coc.b = GetCocFromZValue(coc.b, useExplicit); + coc.a = GetCocFromZValue(coc.a, useExplicit); +#else + half4 coc; + coc.r = GetCocFromDepth(uvDepth + _MainTex_TexelSize.xy * half2(-0.25f,+0.25f), useExplicit); + coc.g = GetCocFromDepth(uvDepth + _MainTex_TexelSize.xy * half2(+0.25f,+0.25f), useExplicit); + coc.b = GetCocFromDepth(uvDepth + _MainTex_TexelSize.xy * half2(+0.25f,-0.25f), useExplicit); + coc.a = GetCocFromDepth(uvDepth + _MainTex_TexelSize.xy * half2(-0.25f,-0.25f), useExplicit); +#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 List m_SimpleProperties = new List(); + private List m_AdvancedProperties = new List(); + + 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); + + if (setting.GetCustomAttributes(typeof(LensAberrations.SimpleSetting), false).Length > 0) + m_SimpleProperties.Add(property); + else if (setting.GetCustomAttributes(typeof(LensAberrations.AdvancedSetting), false).Length > 0) + m_AdvancedProperties.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")) + { + if (group.Key.FieldType == typeof(LensAberrations.VignetteSettings)) + { + if (m_SimpleProperties.Contains(field) && concreteTarget.vignette.mode != LensAberrations.SettingsMode.Simple || + m_AdvancedProperties.Contains(field) && concreteTarget.vignette.mode != LensAberrations.SettingsMode.Advanced) + continue; + } + else + { + if (m_AdvancedProperties.Contains(field) && concreteTarget.chromaticAberration.mode != LensAberrations.SettingsMode.Advanced) + continue; + } + + EditorGUILayout.PropertyField(field); + } + } + GUILayout.EndVertical(); + } + GUILayout.EndHorizontal(); + } + } + + public override void OnInspectorGUI() + { + serializedObject.Update(); + DrawFields(); + serializedObject.ApplyModifiedProperties(); + } + } +} diff --git a/Assets/Cinematic Effects/LensAberrations/Editor/LensAberrationsEditor.cs.meta b/Assets/Cinematic Effects/LensAberrations/Editor/LensAberrationsEditor.cs.meta new file mode 100644 index 0000000..6b7344e --- /dev/null +++ b/Assets/Cinematic Effects/LensAberrations/Editor/LensAberrationsEditor.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 8becb41f431ef90468376f6c5845e0bd +timeCreated: 1454680396 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/LensAberrations/LensAberrations.cs b/Assets/Cinematic Effects/LensAberrations/LensAberrations.cs new file mode 100644 index 0000000..3046820 --- /dev/null +++ b/Assets/Cinematic Effects/LensAberrations/LensAberrations.cs @@ -0,0 +1,328 @@ +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 SimpleSetting : Attribute + {} + + [AttributeUsage(AttributeTargets.Field)] + public class AdvancedSetting : Attribute + {} + #endregion + + #region Settings + public enum SettingsMode + { + Simple, + Advanced + } + + [Serializable] + public struct DistortionSettings + { + public bool enabled; + + [Range(-100f, 100f), Tooltip("Distortion amount.")] + public float amount; + + [Range(0f, 1f), Tooltip("Distortion center point (X axis).")] + public float centerX; + + [Range(0f, 1f), Tooltip("Distortion center point (Y axis).")] + public float centerY; + + [Range(0f, 2f), Tooltip("Amount multiplier on X axis.")] + public float amountX; + + [Range(0f, 2f), Tooltip("Amount multiplier on Y axis.")] + public float amountY; + + [Range(0.5f, 2f), Tooltip("Global screen scaling.")] + public float scale; + + public static DistortionSettings defaultSettings + { + get + { + return new DistortionSettings + { + enabled = false, + amount = 0f, + centerX = 0.5f, + centerY = 0.5f, + amountX = 1f, + amountY = 1f, + scale = 1f + }; + } + } + } + + [Serializable] + public struct VignetteSettings + { + public bool enabled; + + [Tooltip("Use the \"Advanced\" mode if you need more control over the vignette shape and smoothness at the expense of performances.")] + public SettingsMode mode; + + [Tooltip("Vignette color. Use the alpha channel for transparency.")] + public Color color; + + [SimpleSetting, Range(0f, 3f), Tooltip("Amount of vignetting on screen.")] + public float intensity; + + [SimpleSetting, Range(0.1f, 3f), Tooltip("Smoothness of the vignette borders.")] + public float smoothness; + + [AdvancedSetting, Range(0f, 1f), Tooltip("Vignette radius in screen coordinates.")] + public float radius; + + [AdvancedSetting, Range(0f, 1f), Tooltip("Smoothness of the vignette border. Tweak this at the same time as \"Falloff\" to get more control over the vignette gradient.")] + public float spread; + + [AdvancedSetting, Range(0f, 1f), Tooltip("Smoothness of the vignette border. Tweak this at the same time as \"Spread\" to get more control over the vignette gradient.")] + public float falloff; + + [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, + mode = SettingsMode.Simple, + color = Color.black, + intensity = 1.2f, + smoothness = 1.5f, + radius = 0.7f, + spread = 0.4f, + falloff = 0.5f, + roundness = 1f, + blur = 0f, + desaturate = 0f + }; + } + } + } + + [Serializable] + public struct ChromaticAberrationSettings + { + public bool enabled; + + [Tooltip("Use the \"Advanced\" mode if you need more control over the chromatic aberrations at the expense of performances.")] + public SettingsMode mode; + + [Range(-2f, 2f)] + public float tangential; + + [AdvancedSetting, Range(0f, 2f)] + public float axial; + + [AdvancedSetting, Range(0f, 2f)] + public float contrastDependency; + + public static ChromaticAberrationSettings defaultSettings + { + get + { + return new ChromaticAberrationSettings + { + enabled = false, + mode = SettingsMode.Simple, + tangential = 0f, + axial = 0f, + contrastDependency = 0f + }; + } + } + } + #endregion + + [SettingsGroup] + public DistortionSettings distortion = DistortionSettings.defaultSettings; + + [SettingsGroup] + public VignetteSettings vignette = VignetteSettings.defaultSettings; + + [SettingsGroup] + public ChromaticAberrationSettings chromaticAberration = ChromaticAberrationSettings.defaultSettings; + + private enum Pass + { + BlurPrePass, + Simple, + Desaturate, + Blur, + BlurDesaturate, + ChromaticAberrationOnly, + DistortOnly + } + + [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 void OnEnable() + { + if (!ImageEffectHelper.IsSupported(shader, false, false, this)) + enabled = false; + } + + private void OnDisable() + { + if (m_Material != null) + DestroyImmediate(m_Material); + + m_Material = null; + } + + private void OnRenderImage(RenderTexture source, RenderTexture destination) + { + if (!vignette.enabled && !chromaticAberration.enabled && !distortion.enabled) + { + Graphics.Blit(source, destination); + return; + } + + material.DisableKeyword("DISTORT"); + material.DisableKeyword("UNDISTORT"); + + 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); + Vector4 p0 = new Vector4(2f * distortion.centerX - 1f, 2f * distortion.centerY - 1f, distortion.amountX, distortion.amountY); + Vector3 p1 = new Vector3(distortion.amount >= 0f ? theta : 1f / theta, sigma, 1f / distortion.scale); + material.SetVector("_DistCenterScale", p0); + material.SetVector("_DistAmount", p1); + + if (distortion.amount >= 0f) + material.EnableKeyword("DISTORT"); + else + material.EnableKeyword("UNDISTORT"); + } + + material.SetColor("_VignetteColor", vignette.color); + + if (vignette.mode == SettingsMode.Simple) + { + material.SetVector("_Vignette1", new Vector4(vignette.intensity, vignette.smoothness, vignette.blur, 1f - vignette.desaturate)); + material.DisableKeyword("VIGNETTE_ADVANCED"); + } + else + { + float r1 = 0.5f * vignette.radius; + float r2 = r1 + vignette.spread; + float falloff = Math.Max(0.000001f, (1f - vignette.falloff) * 0.5f); + float roundness = (1f - vignette.roundness) * 6f + vignette.roundness * 2f; + material.SetVector("_Vignette1", new Vector4(r1, 1f / (r2 - r1), vignette.blur, 1f - vignette.desaturate)); + material.SetVector("_Vignette2", new Vector3(falloff, 0.5f / falloff, roundness)); + material.EnableKeyword("VIGNETTE_ADVANCED"); + } + + material.DisableKeyword("CHROMATIC_SIMPLE"); + material.DisableKeyword("CHROMATIC_ADVANCED"); + + if (chromaticAberration.enabled && !Mathf.Approximately(chromaticAberration.tangential, 0f)) + { + if (chromaticAberration.mode == SettingsMode.Advanced) + material.EnableKeyword("CHROMATIC_ADVANCED"); + else + material.EnableKeyword("CHROMATIC_SIMPLE"); + + Vector4 chromaParams = new Vector4(2.5f * chromaticAberration.tangential, 5f * chromaticAberration.axial, 5f / Mathf.Max(Mathf.Epsilon, chromaticAberration.contrastDependency), 5f); + material.SetVector("_ChromaticAberration", chromaParams); + } + + if (vignette.enabled && vignette.blur > 0f) + { + // Downscale + gaussian blur (2 passes) + int w = source.width / 2; + int h = source.height / 2; + RenderTexture tmp1 = RenderTexture.GetTemporary(w, h, 0, source.format); + RenderTexture tmp2 = RenderTexture.GetTemporary(w, h, 0, source.format); + + material.SetVector("_BlurPass", new Vector2(1f / w, 0f)); + Graphics.Blit(source, tmp1, material, (int)Pass.BlurPrePass); + material.SetVector("_BlurPass", new Vector2(0f, 1f / h)); + Graphics.Blit(tmp1, tmp2, material, (int)Pass.BlurPrePass); + + material.SetVector("_BlurPass", new Vector2(1f / w, 0f)); + Graphics.Blit(tmp2, tmp1, material, (int)Pass.BlurPrePass); + material.SetVector("_BlurPass", new Vector2(0f, 1f / h)); + Graphics.Blit(tmp1, tmp2, material, (int)Pass.BlurPrePass); + + material.SetTexture("_BlurTex", tmp2); + + if (vignette.desaturate > 0f) + Graphics.Blit(source, destination, material, (int)Pass.BlurDesaturate); + else + Graphics.Blit(source, destination, material, (int)Pass.Blur); + + RenderTexture.ReleaseTemporary(tmp2); + RenderTexture.ReleaseTemporary(tmp1); + } + else if (vignette.enabled && vignette.desaturate > 0f) + { + Graphics.Blit(source, destination, material, (int)Pass.Desaturate); + } + else if (vignette.enabled) + { + Graphics.Blit(source, destination, material, (int)Pass.Simple); + } + else if (chromaticAberration.enabled) + { + Graphics.Blit(source, destination, material, (int)Pass.ChromaticAberrationOnly); + } + else // Distortion enabled + { + Graphics.Blit(source, destination, material, (int)Pass.DistortOnly); + } + } + } +} diff --git a/Assets/Cinematic Effects/LensAberrations/LensAberrations.cs.meta b/Assets/Cinematic Effects/LensAberrations/LensAberrations.cs.meta new file mode 100644 index 0000000..9f89d38 --- /dev/null +++ b/Assets/Cinematic Effects/LensAberrations/LensAberrations.cs.meta @@ -0,0 +1,13 @@ +fileFormatVersion: 2 +guid: ff5335a7357baa3489a469d0ca0f40f3 +timeCreated: 1454589487 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: + - m_Shader: {fileID: 4800000, guid: 136ab50fe2b9ad64d9c22adc3668abb7, type: 3} + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/LensAberrations/Resources.meta b/Assets/Cinematic Effects/LensAberrations/Resources.meta new file mode 100644 index 0000000..711f7b8 --- /dev/null +++ b/Assets/Cinematic Effects/LensAberrations/Resources.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 6580025651e0f284489694492cf3ce61 +folderAsset: yes +timeCreated: 1454583120 +licenseType: Pro +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/LensAberrations/Resources/LensAberrations.shader b/Assets/Cinematic Effects/LensAberrations/Resources/LensAberrations.shader new file mode 100644 index 0000000..19e3550 --- /dev/null +++ b/Assets/Cinematic Effects/LensAberrations/Resources/LensAberrations.shader @@ -0,0 +1,299 @@ +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 + #pragma multi_compile __ DISTORT UNDISTORT + #pragma multi_compile __ CHROMATIC_SIMPLE CHROMATIC_ADVANCED + #pragma multi_compile __ VIGNETTE_ADVANCED + #include "UnityCG.cginc" + #pragma target 3.0 + + sampler2D _MainTex; + float4 _MainTex_TexelSize; + + half4 _DistCenterScale; + half3 _DistAmount; + half4 _ChromaticAberration; + half4 _Vignette1; + half3 _Vignette2; + half4 _VignetteColor; + + sampler2D _BlurTex; + 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 frag_blur_prepass(v2f i) : SV_Target + { + half4 color = tex2D(_MainTex, i.uv); + half3 c = color.rgb * 0.2270270270; + c += tex2D(_MainTex, i.uv1.xy).rgb * 0.3162162162; + c += tex2D(_MainTex, i.uv1.zw).rgb * 0.3162162162; + c += tex2D(_MainTex, i.uv2.xy).rgb * 0.0702702703; + c += tex2D(_MainTex, i.uv2.zw).rgb * 0.0702702703; + return half4(c, color.a); + } + + #define DISK_SAMPLE_NUM 9 + static const half2 SmallDiscKernel[DISK_SAMPLE_NUM] = + { + half2(-0.926212,-0.40581), + half2(-0.695914, 0.457137), + half2(-0.203345, 0.820716), + half2( 0.96234, -0.194983), + half2( 0.473434,-0.480026), + half2( 0.519456, 0.767022), + half2( 0.185461,-0.893124), + half2( 0.89642, 0.412458), + half2(-0.32194, -0.932615), + }; + + half4 chromaticAberration(half4 color, half2 uv) + { +#if CHROMATIC_SIMPLE + half2 coords = (uv - 0.5) * 2.0; + half2 uvg = uv - _MainTex_TexelSize.xy * _ChromaticAberration.x * coords * dot(coords, coords); + color.g = tex2D(_MainTex, uvg).g; +#elif CHROMATIC_ADVANCED + half2 coords = (uv - 0.5) * 2.0; + half tangentialStrength = _ChromaticAberration.x * dot(coords, coords); + half uvg = -(_ChromaticAberration.y > abs(tangentialStrength) ? sign(tangentialStrength) * _ChromaticAberration.y : tangentialStrength); + half2 offset = _MainTex_TexelSize.xy * uvg * coords; + half3 blurredTap = color.rgb * 0.1; + + for (int l = 0; l < DISK_SAMPLE_NUM; l++) + { + half2 sampleUV = uv + _MainTex_TexelSize.xy * SmallDiscKernel[l].xy + offset; + half3 tap = tex2D(_MainTex, sampleUV).rgb; + blurredTap += tap; + } + + blurredTap /= (half)DISK_SAMPLE_NUM + 0.2; + half contrast = saturate(_ChromaticAberration.z * Luminance(abs(blurredTap - color.rgb))); + color.g = lerp(color.g, blurredTap.g, contrast); +#endif + return color; + } + + half2 distort(half2 uv) + { +#if DISTORT + uv = (uv - 0.5) * _DistAmount.z + 0.5; + half2 ruv = _DistCenterScale.zw * (uv - 0.5 - _DistCenterScale.xy); + half ru = length(ruv); + half wu = ru * _DistAmount.x; + ru = tan(wu) * (1.0 / (ru * _DistAmount.y)); + uv = uv + ruv * (ru - 1.0); +#elif UNDISTORT + uv = (uv - 0.5) * _DistAmount.z + 0.5; + half2 ruv = _DistCenterScale.zw * (uv - 0.5 - _DistCenterScale.xy); + half ru = length(ruv); + ru = (1.0 / ru) * _DistAmount.x * atan(ru * _DistAmount.y); + uv = uv + ruv * (ru - 1.0); +#endif + return uv; + } + + half get_vignette_factor(half2 uv) + { +#if VIGNETTE_ADVANCED + uv = abs(uv - 0.5); + half x = saturate((pow(pow(uv.x, _Vignette2.z) + pow(uv.y, _Vignette2.z), 1.0 / _Vignette2.z) - _Vignette1.x) * _Vignette1.y); + half ix = 1.0 - x; + half v = _Vignette2.x == 0.5 ? x : x <= _Vignette2.x ? x * x / ((2.0 - _Vignette2.y) * x + _Vignette2.x * (_Vignette2.y - 1.0)) : 1.0 + ix * ix / ((_Vignette2.y - 2.0) * ix + (_Vignette2.x - 1.0) * (_Vignette2.y - 1.0)); + return 1.0 - v; +#else + half2 d = (uv - 0.5) * _Vignette1.x; + return pow(saturate(1.0 - dot(d, d)), _Vignette1.y); +#endif + } + + half4 vignette_simple(half4 color, half2 uv) + { + half v = get_vignette_factor(uv); + color.rgb = lerp(_VignetteColor.rgb, color.rgb, lerp(1.0, v, _VignetteColor.a)); + return color; + } + + half4 vignette_desat(half4 color, half2 uv) + { + half v = get_vignette_factor(uv); + half lum = Luminance(color); + color.rgb = lerp(lerp(lum.xxx, color.rgb, _Vignette1.w), color.rgb, v); + color.rgb = lerp(_VignetteColor.rgb, color.rgb, lerp(1.0, v, _VignetteColor.a)); + return color; + } + + half4 vignette_blur(half4 color, half2 uv) + { + half2 coords = (uv - 0.5) * 2.0; + half v = get_vignette_factor(uv); + half3 blur = tex2D(_BlurTex, uv); + color.rgb = lerp(color.rgb, blur, saturate(_Vignette1.z * dot(coords, coords))); + color.rgb = lerp(_VignetteColor.rgb, color.rgb, lerp(1.0, v, _VignetteColor.a)); + return color; + } + + half4 vignette_blur_desat(half4 color, half2 uv) + { + half2 coords = (uv - 0.5) * 2.0; + half v = get_vignette_factor(uv); + half3 blur = tex2D(_BlurTex, uv); + color.rgb = lerp(color.rgb, blur, saturate(_Vignette1.z * dot(coords, coords))); + half lum = Luminance(color); + color.rgb = lerp(lerp(lum.xxx, color.rgb, _Vignette1.w), color.rgb, v); + color.rgb = lerp(_VignetteColor.rgb, color.rgb, lerp(1.0, v, _VignetteColor.a)); + return color; + } + + half4 frag_simple(v2f_img i) : SV_Target + { + half2 uv = distort(i.uv); + half4 color = tex2D(_MainTex, uv); + color = chromaticAberration(color, uv); + color = vignette_simple(color, uv); + return color; + } + + half4 frag_desat(v2f_img i) : SV_Target + { + half2 uv = distort(i.uv); + half4 color = tex2D(_MainTex, uv); + color = chromaticAberration(color, uv); + color = vignette_desat(color, uv); + return color; + } + + half4 frag_blur(v2f_img i) : SV_Target + { + half2 uv = distort(i.uv); + half4 color = tex2D(_MainTex, uv); + color = chromaticAberration(color, uv); + color = vignette_blur(color, uv); + return color; + } + + half4 frag_blur_desat(v2f_img i) : SV_Target + { + half2 uv = distort(i.uv); + half4 color = tex2D(_MainTex, uv); + color = chromaticAberration(color, uv); + color = vignette_blur_desat(color, uv); + return color; + } + + half4 frag_chroma_only(v2f_img i) : SV_Target + { + half2 uv = distort(i.uv); + half4 color = tex2D(_MainTex, uv); + color = chromaticAberration(color, uv); + return color; + } + + half4 frag_distort_only(v2f_img i) : SV_Target + { + half2 uv = distort(i.uv); + return tex2D(_MainTex, uv); + } + + ENDCG + + // (0) Blur pre-pass + Pass + { + CGPROGRAM + #pragma vertex vert_blur_prepass + #pragma fragment frag_blur_prepass + ENDCG + } + + // (1) Vignette simple + Pass + { + CGPROGRAM + #pragma vertex vert_img + #pragma fragment frag_simple + ENDCG + } + + // (2) Vignette desat + Pass + { + CGPROGRAM + #pragma vertex vert_img + #pragma fragment frag_desat + ENDCG + } + + // (3) Vignette blur + Pass + { + CGPROGRAM + #pragma vertex vert_img + #pragma fragment frag_blur + ENDCG + } + + // (4) Vignette blur desat + Pass + { + CGPROGRAM + #pragma vertex vert_img + #pragma fragment frag_blur_desat + ENDCG + } + + // (5) Chromatic aberration only + Pass + { + CGPROGRAM + #pragma vertex vert_img + #pragma fragment frag_chroma_only + ENDCG + } + + // (6) Distort only + Pass + { + CGPROGRAM + #pragma vertex vert_img + #pragma fragment frag_distort_only + ENDCG + } + } + FallBack off +} diff --git a/Assets/Cinematic Effects/LensAberrations/Resources/LensAberrations.shader.meta b/Assets/Cinematic Effects/LensAberrations/Resources/LensAberrations.shader.meta new file mode 100644 index 0000000..e89bc32 --- /dev/null +++ b/Assets/Cinematic Effects/LensAberrations/Resources/LensAberrations.shader.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 136ab50fe2b9ad64d9c22adc3668abb7 +timeCreated: 1454583143 +licenseType: Pro +ShaderImporter: + defaultTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/MotionBlur.meta b/Assets/Cinematic Effects/MotionBlur.meta new file mode 100644 index 0000000..ada916f --- /dev/null +++ b/Assets/Cinematic Effects/MotionBlur.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 22361d70f5bd34f35be82589af855289 +folderAsset: yes +timeCreated: 1461976949 +licenseType: Pro +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/MotionBlur/Plugins.meta b/Assets/Cinematic Effects/MotionBlur/Plugins.meta new file mode 100644 index 0000000..ee24b52 --- /dev/null +++ b/Assets/Cinematic Effects/MotionBlur/Plugins.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 01c03782ff2da4717ae56fc9d4e95223 +folderAsset: yes +timeCreated: 1461976949 +licenseType: Pro +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/MotionBlur/Plugins/AmplifyMotion.dll b/Assets/Cinematic Effects/MotionBlur/Plugins/AmplifyMotion.dll new file mode 100644 index 0000000000000000000000000000000000000000..8ce8d8ca2d3e1c0239438045be14c55d3c606e72 GIT binary patch literal 3584 zcmeHJ-D@0G6hE`ONjHrRsUO8)sgtAup)xFWOQra+n{3qRZWA(_D7ui$?A~rhXXXww zvo-NS;)4(RAc7!$RrEm+@u6UmYW)WaKKLluH=jfwMZx$xcV>38wrCL_6myb$?m6fF z&bjBDnYnix&%aH1A}V0)?GatU%v4eQ&)F`PC+`1zf-a9;pT45iuTM9(oJbEs*$pjE zZ(F`EW8D^d*z)CEMC^tQ>jT4Q+!UJTm zgN{+bAevNiF3Fn>oWG)7aM+phRC%4D{6Cmel}(^;XNi_ssG#=LkJUbH65RpigBhaZ zedBEiI#F>StO)(7eYz2g?HGEQ6UUmW^AG#OylI3{*v7KTtpb7Z`vXITxnhLEl>l3ekKfXY(ZY6~wvaXoOaDq9%MbHvSEoH=mx@Qg7b=;%TE~oGG0>eU^ib zkPChpWA;^)jZMC0*^EQS??w>mC)l{W*)@}XhRly{_Q|!S8s;MMsSmr@=IGso7VVa{uD&i=;Miw5yd*Dn7lIs|w7vM1kK1tKy z_mDy3&<(naX29>GQ&iZ6%Me|IhRph;4c?tc8nV-K#bZ?U0@t~)(~z+veWT;L%iE2=TNW%pu{+R!IRbF0K(>oh4J@e6-50~G% z&M@n+hmvaxz<`F!l+eq zWLLIop$u%f-AeP<7ebK~o>`K|&@yE&Y>Sq(Uu;#QNW>;uD$2tkBk0(w=6^dYq~A8@ zd4gq~rJE@`1Co`E1sT>{w_!Pc@(Up6AAifv+sv2e$5REL z_|Qqp<{E~Es1}8YlDteO)g{@)ss(F=b&F!)B(#J+EnLMRp&_RjC literal 0 HcmV?d00001 diff --git a/Assets/Cinematic Effects/MotionBlur/Plugins/AmplifyMotion.dll.meta b/Assets/Cinematic Effects/MotionBlur/Plugins/AmplifyMotion.dll.meta new file mode 100644 index 0000000..ed556df --- /dev/null +++ b/Assets/Cinematic Effects/MotionBlur/Plugins/AmplifyMotion.dll.meta @@ -0,0 +1,22 @@ +fileFormatVersion: 2 +guid: f4044b596510fe5489da703d40efc52b +PluginImporter: + serializedVersion: 1 + iconMap: {} + executionOrder: {} + isPreloaded: 0 + platformData: + Any: + enabled: 1 + settings: {} + Editor: + enabled: 0 + settings: + DefaultValueInitialized: true + WindowsStoreApps: + enabled: 0 + settings: + CPU: AnyCPU + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/MotionBlur/Plugins/AmplifyMotionBase.cs b/Assets/Cinematic Effects/MotionBlur/Plugins/AmplifyMotionBase.cs new file mode 100644 index 0000000..7e391fe --- /dev/null +++ b/Assets/Cinematic Effects/MotionBlur/Plugins/AmplifyMotionBase.cs @@ -0,0 +1,1167 @@ +// Amplify Motion - Full-scene Motion Blur for Unity Pro +// Copyright (c) Amplify Creations, Lda + +#if UNITY_4_0 || UNITY_4_1 || UNITY_4_2 || UNITY_4_3 || UNITY_4_4 || UNITY_4_5 || UNITY_4_6 || UNITY_4_7 || UNITY_4_8 || UNITY_4_9 +#define UNITY_4 +#endif +#if UNITY_5_0 || UNITY_5_1 || UNITY_5_2 || UNITY_5_3 || UNITY_5_4 || UNITY_5_5 || UNITY_5_6 || UNITY_5_7 || UNITY_5_8 || UNITY_5_9 +#define UNITY_5 +#endif +#if UNITY_4 || UNITY_5_0 || UNITY_5_1 || UNITY_5_2 +#define UNITY_PRE_5_3 +#endif + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using UnityEngine; +#if !UNITY_4 +using UnityEngine.Rendering; +#endif +using UnityEngine.Serialization; + +namespace AmplifyMotion +{ + public enum Quality + { + Mobile = 0, + Standard = 1, + Standard_SM3 = 2, + SoftEdge_SM3 = 3 + } +} + +[RequireComponent( typeof( Camera ) )] +[AddComponentMenu( "" )] +public class AmplifyMotionEffectBase : MonoBehaviour +{ + public AmplifyMotion.Quality QualityLevel = AmplifyMotion.Quality.Standard; + public bool AutoRegisterObjs = true; + public Camera[] OverlayCameras = new Camera[ 0 ]; + public LayerMask CullingMask = ~0; + public int QualitySteps = 1; + public float MotionScale = 3.0f; + public float CameraMotionMult = 1.0f; + public float MinVelocity = 1.0f; + public float MaxVelocity = 10.0f; + public float DepthThreshold = 0.001f; + [FormerlySerializedAs( "workerThreads" )] public int WorkerThreads = 0; + public bool SystemThreadPool = false; + public bool ForceCPUOnly = false; + public bool DebugMode = false; + + // For compatibility + [Obsolete( "workerThreads is deprecated, please use WorkerThreads instead." )] + public int workerThreads { get { return WorkerThreads; } set { WorkerThreads = value; } } + + private Camera m_camera; + private bool m_starting = true; + + private int m_width, m_height; + private RenderTexture m_motionRT; +#if UNITY_4 + private Texture m_dummyTex; +#endif + private Material m_blurMaterial; + private Material m_solidVectorsMaterial; + private Material m_skinnedVectorsMaterial; + private Material m_clothVectorsMaterial; + private Material m_reprojectionMaterial; + private Material m_combineMaterial; + private Material m_dilationMaterial; + private Material m_depthMaterial; + private Material m_debugMaterial; + + internal Material SolidVectorsMaterial { get { return m_solidVectorsMaterial; } } + internal Material SkinnedVectorsMaterial { get { return m_skinnedVectorsMaterial; } } + internal Material ClothVectorsMaterial { get { return m_clothVectorsMaterial; } } + + internal RenderTexture MotionRenderTexture { get { return m_motionRT; } } + +#if TRIAL + private Texture2D m_watermark; +#endif + + private Dictionary m_linkedCameras = new Dictionary(); + public Dictionary LinkedCameras { get { return m_linkedCameras; } } + internal Camera[] m_linkedCameraKeys = null; + internal AmplifyMotionCamera[] m_linkedCameraValues = null; + internal bool m_linkedCamerasChanged = true; + + private AmplifyMotionPostProcess m_currentPostProcess = null; + + private int m_globalObjectId = 1; + + private float m_deltaTime; + private float m_fixedDeltaTime; + + private float m_motionScaleNorm; + private float m_fixedMotionScaleNorm; + + internal float MotionScaleNorm { get { return m_motionScaleNorm; } } + internal float FixedMotionScaleNorm { get { return m_fixedMotionScaleNorm; } } + + private AmplifyMotion.Quality m_qualityLevel; + + private AmplifyMotionCamera m_baseCamera = null; + public AmplifyMotionCamera BaseCamera { get { return m_baseCamera; } } + + private AmplifyMotion.WorkerThreadPool m_workerThreadPool = null; + internal AmplifyMotion.WorkerThreadPool WorkerPool { get { return m_workerThreadPool; } } + + // GLOBAL OBJECT MANAGEMENT + public static Dictionary m_activeObjects = new Dictionary(); + public static Dictionary m_activeCameras = new Dictionary(); + + private static bool m_isD3D = false; + public static bool IsD3D { get { return m_isD3D; } } + + private bool m_canUseGPU = false; + public bool CanUseGPU { get { return m_canUseGPU; } } + +#if !UNITY_4 + private const CameraEvent m_updateCBEvent = CameraEvent.BeforeImageEffectsOpaque; + private CommandBuffer m_updateCB = null; + + private const CameraEvent m_fixedUpdateCBEvent = CameraEvent.BeforeImageEffectsOpaque; + private CommandBuffer m_fixedUpdateCB = null; + + private const CameraEvent m_renderCBEvent = CameraEvent.BeforeImageEffects; + private CommandBuffer m_renderCB = null; +#endif + + private static bool m_ignoreMotionScaleWarning = false; + public static bool IgnoreMotionScaleWarning { get { return m_ignoreMotionScaleWarning; } } + + private static AmplifyMotionEffectBase m_firstInstance = null; + public static AmplifyMotionEffectBase FirstInstance { get { return m_firstInstance; } } + public static AmplifyMotionEffectBase Instance { get { return m_firstInstance; } } + + void Awake() + { + if ( m_firstInstance == null ) + m_firstInstance = this; + + m_isD3D = SystemInfo.graphicsDeviceVersion.StartsWith( "Direct3D" ); + m_globalObjectId = 1; + m_width = m_height = 0; + + if ( ForceCPUOnly ) + m_canUseGPU = false; + else + { + #if !UNITY_4 + bool hasRTs = SystemInfo.supportsRenderTextures; + bool hasSM3 = ( SystemInfo.graphicsShaderLevel >= 30 ); + bool hasRHalfTex = SystemInfo.SupportsTextureFormat( TextureFormat.RHalf ); + bool hasRGHalfTex = SystemInfo.SupportsTextureFormat( TextureFormat.RGHalf ); + bool hasARGBHalfTex = SystemInfo.SupportsTextureFormat( TextureFormat.RGBAHalf ); + bool hasARGBFloatRT = SystemInfo.SupportsRenderTextureFormat( RenderTextureFormat.ARGBFloat ); + + m_canUseGPU = hasRTs && hasSM3 && hasRHalfTex && hasRGHalfTex && hasARGBHalfTex && hasARGBFloatRT; + #endif + } + } + + internal void ResetObjectId() + { + m_globalObjectId = 1; + } + + internal int GenerateObjectId( GameObject obj ) + { + // id = 0, static objs + // id = 255, excluded objs + + if ( obj.isStatic ) + return 0; // same as background + + m_globalObjectId++; + + // TEMPORARY FIX: wrap around; may cause artifacts on id collision of nearby objs + if ( m_globalObjectId > 254 ) + m_globalObjectId = 1; + + return m_globalObjectId; + } + + void SafeDestroyMaterial( ref Material mat ) + { + if ( mat != null ) + { + DestroyImmediate( mat ); + mat = null; + } + } + + bool CheckMaterialAndShader( Material material, string name ) + { + bool ok = true; + if ( material == null || material.shader == null ) + { + Debug.LogWarning( "[AmplifyMotion] Error creating " + name + " material" ); + ok = false; + } + else if ( !material.shader.isSupported ) + { + Debug.LogWarning( "[AmplifyMotion] " + name + " shader not supported on this platform" ); + ok = false; + } + return ok; + } + + void DestroyMaterials() + { + SafeDestroyMaterial( ref m_blurMaterial ); + SafeDestroyMaterial( ref m_solidVectorsMaterial ); + SafeDestroyMaterial( ref m_skinnedVectorsMaterial ); + SafeDestroyMaterial( ref m_clothVectorsMaterial ); + SafeDestroyMaterial( ref m_reprojectionMaterial ); + SafeDestroyMaterial( ref m_combineMaterial ); + SafeDestroyMaterial( ref m_dilationMaterial ); + SafeDestroyMaterial( ref m_depthMaterial ); + SafeDestroyMaterial( ref m_debugMaterial ); + } + + bool CreateMaterials() + { + DestroyMaterials(); + + int shaderModel = ( SystemInfo.graphicsShaderLevel >= 30 ) ? 3 : 2; + + string blurShader = "Hidden/Amplify Motion/MotionBlurSM" + shaderModel; + string solidVectorsShader = "Hidden/Amplify Motion/SolidVectors"; + string skinnedVectorsShader = "Hidden/Amplify Motion/SkinnedVectors"; + string clothVectorsShader = "Hidden/Amplify Motion/ClothVectors"; + string reprojectionVectorsShader = "Hidden/Amplify Motion/ReprojectionVectors"; + string combineShader = "Hidden/Amplify Motion/Combine"; + string dilationShader = "Hidden/Amplify Motion/Dilation"; + string depthShader = "Hidden/Amplify Motion/Depth"; + string debugShader = "Hidden/Amplify Motion/Debug"; + + try + { + m_blurMaterial = new Material( Shader.Find( blurShader ) ) { hideFlags = HideFlags.DontSave }; + m_solidVectorsMaterial = new Material( Shader.Find( solidVectorsShader ) ) { hideFlags = HideFlags.DontSave }; + m_skinnedVectorsMaterial = new Material( Shader.Find( skinnedVectorsShader ) ) { hideFlags = HideFlags.DontSave }; + m_clothVectorsMaterial = new Material( Shader.Find( clothVectorsShader ) ) { hideFlags = HideFlags.DontSave }; + m_reprojectionMaterial = new Material( Shader.Find( reprojectionVectorsShader ) ) { hideFlags = HideFlags.DontSave }; + m_combineMaterial = new Material( Shader.Find( combineShader ) ) { hideFlags = HideFlags.DontSave }; + m_dilationMaterial = new Material( Shader.Find( dilationShader ) ) { hideFlags = HideFlags.DontSave }; + m_depthMaterial = new Material( Shader.Find( depthShader ) ) { hideFlags = HideFlags.DontSave }; + m_debugMaterial = new Material( Shader.Find( debugShader ) ) { hideFlags = HideFlags.DontSave }; + } + catch ( Exception ) + { + } + + // even if we fail, we still need to know which one failed + bool ok = CheckMaterialAndShader( m_blurMaterial, blurShader ); + ok = ok && CheckMaterialAndShader( m_solidVectorsMaterial, solidVectorsShader ); + ok = ok && CheckMaterialAndShader( m_skinnedVectorsMaterial, skinnedVectorsShader ); + ok = ok && CheckMaterialAndShader( m_clothVectorsMaterial, clothVectorsShader ); + ok = ok && CheckMaterialAndShader( m_reprojectionMaterial, reprojectionVectorsShader ); + ok = ok && CheckMaterialAndShader( m_combineMaterial, combineShader ); + ok = ok && CheckMaterialAndShader( m_dilationMaterial, dilationShader ); + ok = ok && CheckMaterialAndShader( m_depthMaterial, depthShader ); + ok = ok && CheckMaterialAndShader( m_debugMaterial, debugShader ); + return ok; + } + + RenderTexture CreateRenderTexture( string name, int depth, RenderTextureFormat fmt, RenderTextureReadWrite rw, FilterMode fm ) + { + RenderTexture rt = new RenderTexture( m_width, m_height, depth, fmt, rw ); + rt.hideFlags = HideFlags.DontSave; + rt.name = name; + rt.wrapMode = TextureWrapMode.Clamp; + rt.filterMode = fm; + rt.Create(); + return rt; + } + + void SafeDestroyRenderTexture( ref RenderTexture rt ) + { + if ( rt != null ) + { + RenderTexture.active = null; + rt.Release(); + DestroyImmediate( rt ); + rt = null; + } + } + + void SafeDestroyTexture( ref Texture tex ) + { + if ( tex != null ) + { + DestroyImmediate( tex ); + tex = null; + } + } + + void DestroyRenderTextures() + { + RenderTexture.active = null; + + SafeDestroyRenderTexture( ref m_motionRT ); + + #if UNITY_4 + SafeDestroyTexture( ref m_dummyTex ); + if ( m_dummyTex != null ) + { + DestroyImmediate( m_dummyTex ); + m_dummyTex = null; + } + #endif + } + + void UpdateRenderTextures( bool qualityChanged ) + { + int screenWidth = Mathf.FloorToInt( m_camera.pixelWidth + 0.5f ); + int screenHeight = Mathf.FloorToInt( m_camera.pixelHeight + 0.5f ); + + if ( QualityLevel == AmplifyMotion.Quality.Mobile ) + { + screenWidth /= 2; + screenHeight /= 2; + } + + if ( m_width != screenWidth || m_height != screenHeight || qualityChanged ) + { + m_width = screenWidth; + m_height = screenHeight; + + DestroyRenderTextures(); + } + + if ( m_motionRT == null ) + m_motionRT = CreateRenderTexture( "AM-MotionVectors", 24, RenderTextureFormat.ARGB32, RenderTextureReadWrite.Linear, FilterMode.Point ); + + #if UNITY_4 + if ( m_dummyTex == null ) + { + m_dummyTex = new Texture2D( 4, 4, TextureFormat.ARGB32, false, true ); + m_dummyTex.wrapMode = TextureWrapMode.Clamp; + m_dummyTex.hideFlags = HideFlags.DontSave; + } + #endif + } + + public bool CheckSupport() + { + if ( !SystemInfo.supportsImageEffects || !SystemInfo.supportsRenderTextures ) + { + Debug.LogError( "[AmplifyMotion] Initialization failed. This plugin requires support for Image Effects and Render Textures." ); + return false; + } + return true; + } + + void InitializeThreadPool() + { + if ( WorkerThreads <= 0 ) + WorkerThreads = Mathf.Max( Environment.ProcessorCount / 2, 1 ); // half of CPU threads; non-busy idle + + m_workerThreadPool = new AmplifyMotion.WorkerThreadPool(); + m_workerThreadPool.InitializeAsyncUpdateThreads( WorkerThreads, SystemThreadPool ); + } + + void ShutdownThreadPool() + { + if ( m_workerThreadPool != null ) + { + m_workerThreadPool.FinalizeAsyncUpdateThreads(); + m_workerThreadPool = null; + } + } + + void InitializeCommandBuffers() + { + #if !UNITY_4 + ShutdownCommandBuffers(); + + m_updateCB = new CommandBuffer(); + m_updateCB.name = "AmplifyMotion.Update"; + m_camera.AddCommandBuffer( m_updateCBEvent, m_updateCB ); + + m_fixedUpdateCB = new CommandBuffer(); + m_fixedUpdateCB.name = "AmplifyMotion.FixedUpdate"; + m_camera.AddCommandBuffer( m_fixedUpdateCBEvent, m_fixedUpdateCB ); + + m_renderCB = new CommandBuffer(); + m_renderCB.name = "AmplifyMotion.Render"; + m_camera.AddCommandBuffer( m_renderCBEvent, m_renderCB ); + + #endif + } + + void ShutdownCommandBuffers() + { + #if !UNITY_4 + if ( m_updateCB != null ) + { + m_camera.RemoveCommandBuffer( m_updateCBEvent, m_updateCB ); + m_updateCB.Release(); + m_updateCB = null; + } + if ( m_fixedUpdateCB != null ) + { + m_camera.RemoveCommandBuffer( m_fixedUpdateCBEvent, m_fixedUpdateCB ); + m_fixedUpdateCB.Release(); + m_fixedUpdateCB = null; + } + if ( m_renderCB != null ) + { + m_camera.RemoveCommandBuffer( m_renderCBEvent, m_renderCB ); + m_renderCB.Release(); + m_renderCB = null; + } + #endif + } + + void OnEnable() + { + m_camera = GetComponent(); + + if ( !CheckSupport() ) + { + enabled = false; + return; + } + + InitializeThreadPool(); + + m_starting = true; + + if ( !CreateMaterials() ) + { + Debug.LogError( "[AmplifyMotion] Failed loading or compiling necessary shaders. Please try reinstalling Amplify Motion or contact support@amplify.pt" ); + enabled = false; + return; + } + + if ( AutoRegisterObjs ) + UpdateActiveObjects(); + + InitializeCameras(); + InitializeCommandBuffers(); + + UpdateRenderTextures( true ); + + m_linkedCameras.TryGetValue( m_camera, out m_baseCamera ); + + if ( m_baseCamera == null ) + { + Debug.LogError( "[AmplifyMotion] Failed setting up Base Camera. Please contact support@amplify.pt" ); + enabled = false; + return; + } + if ( m_currentPostProcess != null ) + m_currentPostProcess.enabled = true; + + m_qualityLevel = QualityLevel; + } + + void OnDisable() + { + if ( m_currentPostProcess != null ) + m_currentPostProcess.enabled = false; + + ShutdownCommandBuffers(); + ShutdownThreadPool(); + } + + void Start() + { + UpdatePostProcess(); + +#if TRIAL + m_watermark = new Texture2D( 4, 4 ); + m_watermark.LoadImage( AmplifyMotion.Watermark.ImageData ); +#endif + } + + internal void RemoveCamera( Camera reference ) + { + m_linkedCameras.Remove( reference ); + } + + void OnDestroy() + { + AmplifyMotionCamera[] prevLinkedCams = m_linkedCameras.Values.ToArray(); + + foreach ( AmplifyMotionCamera cam in prevLinkedCams ) + { + if ( cam != null && cam.gameObject != gameObject ) + { + Camera actual = cam.GetComponent(); + if ( actual != null ) + actual.targetTexture = null; + DestroyImmediate( cam ); + } + } + + DestroyRenderTextures(); + DestroyMaterials(); +#if TRIAL + DestroyImmediate( m_watermark ); +#endif + } + + GameObject RecursiveFindCamera( GameObject obj, string auxCameraName ) + { + GameObject cam = null; + if ( obj.name == auxCameraName ) + cam = obj; + else + { + foreach ( Transform child in obj.transform ) + { + cam = RecursiveFindCamera( child.gameObject, auxCameraName ); + if ( cam != null ) + break; + } + } + return cam; + } + + void InitializeCameras() + { + List cleanOverlayCameras = new List( OverlayCameras.Length ); + for ( int i = 0; i < OverlayCameras.Length; i++ ) + { + if ( OverlayCameras[ i ] != null ) + cleanOverlayCameras.Add( OverlayCameras[ i ] ); + } + + Camera[] referenceCameras = new Camera[ cleanOverlayCameras.Count + 1 ]; + + referenceCameras[ 0 ] = m_camera; + for ( int i = 0; i < cleanOverlayCameras.Count; i++ ) + referenceCameras[ i + 1 ] = cleanOverlayCameras[ i ]; + + m_linkedCameras.Clear(); + + for ( int i = 0; i < referenceCameras.Length; i++ ) + { + Camera reference = referenceCameras[ i ]; + if ( !m_linkedCameras.ContainsKey( reference ) ) + { + AmplifyMotionCamera cam = reference.gameObject.GetComponent(); + if ( cam != null ) + { + cam.enabled = false; + cam.enabled = true; + } + else + cam = reference.gameObject.AddComponent(); + + cam.LinkTo( this, i > 0 ); + + m_linkedCameras.Add( reference, cam ); + m_linkedCamerasChanged = true; + } + } + } + + public void UpdateActiveCameras() + { + InitializeCameras(); + } + + internal static void RegisterCamera( AmplifyMotionCamera cam ) + { + m_activeCameras.Add( cam.GetComponent(), cam ); + foreach ( AmplifyMotionObjectBase obj in m_activeObjects.Values ) + obj.RegisterCamera( cam ); + } + + internal static void UnregisterCamera( AmplifyMotionCamera cam ) + { + foreach ( AmplifyMotionObjectBase obj in m_activeObjects.Values ) + obj.UnregisterCamera( cam ); + m_activeCameras.Remove( cam.GetComponent() ); + } + + public void UpdateActiveObjects() + { + GameObject[] gameObjs = FindObjectsOfType( typeof( GameObject ) ) as GameObject[]; + for ( int i = 0; i < gameObjs.Length; i++ ) + { + if ( !m_activeObjects.ContainsKey( gameObjs[ i ] ) ) + TryRegister( gameObjs[ i ], true ); + } + } + + internal static void RegisterObject( AmplifyMotionObjectBase obj ) + { + m_activeObjects.Add( obj.gameObject, obj ); + foreach ( AmplifyMotionCamera cam in m_activeCameras.Values ) + obj.RegisterCamera( cam ); + } + + internal static void UnregisterObject( AmplifyMotionObjectBase obj ) + { + foreach ( AmplifyMotionCamera cam in m_activeCameras.Values ) + obj.UnregisterCamera( cam ); + m_activeObjects.Remove( obj.gameObject ); + } + + internal static bool FindValidTag( Material[] materials ) + { + for ( int i = 0; i < materials.Length; i++ ) + { + Material mat = materials[ i ]; + if ( mat != null ) + { + string tag = mat.GetTag( "RenderType", false ); + if ( tag == "Opaque" || tag == "TransparentCutout" ) + #if UNITY_4 + return true; + #else + return !mat.IsKeywordEnabled( "_ALPHABLEND_ON" ) && !mat.IsKeywordEnabled( "_ALPHAPREMULTIPLY_ON" ); + #endif + } + } + return false; + } + + internal static bool CanRegister( GameObject gameObj, bool autoReg ) + { + // Ignore static objects + if ( gameObj.isStatic ) + return false; + + // Ignore invalid materials; Ignore static batches + Renderer renderer = gameObj.GetComponent(); + if ( renderer == null || renderer.sharedMaterials == null || renderer.isPartOfStaticBatch ) + return false; + + // Ignore disabled renderer + if ( !renderer.enabled ) + return false; + + // Ignore if visible only for shadows + #if !UNITY_4 + if ( renderer.shadowCastingMode == UnityEngine.Rendering.ShadowCastingMode.ShadowsOnly ) + return false; + #endif + + if ( renderer.GetType() == typeof( SpriteRenderer ) ) + { + return false; + } + else + { + // Ignore unsupported RenderType + if ( !FindValidTag( renderer.sharedMaterials ) ) + return false; + + #if UNITY_4 + if ( renderer.GetType() == typeof( ClothRenderer ) ) + { + if ( gameObj.GetComponent().tearFactor != 0.0f ) + Debug.LogWarning( "[AmplifyMotion] Tearable cloth objects are not supported at this time. Ignoring cloth object \"" + renderer.name + "\"" ); + else + return true; + } + #endif + + // Only valid and supported renderers + Type type = renderer.GetType(); + if ( type == typeof( MeshRenderer ) || type == typeof( SkinnedMeshRenderer ) ) + { + return true; + } + + #if !UNITY_PRE_5_3 + if ( type == typeof( ParticleSystemRenderer ) && !autoReg ) + { + // Only supported ParticleSystem modes + ParticleSystemRenderMode mode = ( renderer as ParticleSystemRenderer ).renderMode; + return ( mode == ParticleSystemRenderMode.Mesh || mode == ParticleSystemRenderMode.Billboard ); + } + #endif + } + + return false; + } + + internal static void TryRegister( GameObject gameObj, bool autoReg ) + { + if ( CanRegister( gameObj, autoReg ) && gameObj.GetComponent() == null ) + { + AmplifyMotionObjectBase.ApplyToChildren = false; + gameObj.AddComponent(); + AmplifyMotionObjectBase.ApplyToChildren = true; + } + } + + internal static void TryUnregister( GameObject gameObj ) + { + AmplifyMotionObjectBase comp = gameObj.GetComponent(); + if ( comp != null ) + Destroy( comp ); + } + + public void Register( GameObject gameObj ) + { + if ( !m_activeObjects.ContainsKey( gameObj ) ) + TryRegister( gameObj, false ); + } + + public static void RegisterS( GameObject gameObj ) + { + if ( !m_activeObjects.ContainsKey( gameObj ) ) + TryRegister( gameObj, false ); + } + + public void RegisterRecursively( GameObject gameObj ) + { + if ( !m_activeObjects.ContainsKey( gameObj ) ) + TryRegister( gameObj, false ); + + foreach ( Transform child in gameObj.transform ) + RegisterRecursively( child.gameObject ); + } + + public static void RegisterRecursivelyS( GameObject gameObj ) + { + if ( !m_activeObjects.ContainsKey( gameObj ) ) + TryRegister( gameObj, false ); + + foreach ( Transform child in gameObj.transform ) + RegisterRecursivelyS( child.gameObject ); + } + + public void Unregister( GameObject gameObj ) + { + if ( m_activeObjects.ContainsKey( gameObj ) ) + TryUnregister( gameObj ); + } + + public static void UnregisterS( GameObject gameObj ) + { + if ( m_activeObjects.ContainsKey( gameObj ) ) + TryUnregister( gameObj ); + } + + public void UnregisterRecursively( GameObject gameObj ) + { + if ( m_activeObjects.ContainsKey( gameObj ) ) + TryUnregister( gameObj ); + + foreach ( Transform child in gameObj.transform ) + UnregisterRecursively( child.gameObject ); + } + + public static void UnregisterRecursivelyS( GameObject gameObj ) + { + if ( m_activeObjects.ContainsKey( gameObj ) ) + TryUnregister( gameObj ); + + foreach ( Transform child in gameObj.transform ) + UnregisterRecursivelyS( child.gameObject ); + } + + void UpdatePostProcess() + { + Camera highestReference = null; + float highestDepth = -float.MaxValue; + + if ( m_linkedCamerasChanged ) + UpdateLinkedCameras(); + + for ( int i = 0; i < m_linkedCameraKeys.Length; i++ ) + { + if ( m_linkedCameraKeys[ i ] != null && m_linkedCameraKeys[ i ].isActiveAndEnabled && m_linkedCameraKeys[ i ].depth > highestDepth ) + { + highestReference = m_linkedCameraKeys[ i ]; + highestDepth = m_linkedCameraKeys[ i ].depth; + } + } + + if ( m_currentPostProcess != null && m_currentPostProcess.gameObject != highestReference.gameObject ) + { + DestroyImmediate( m_currentPostProcess ); + m_currentPostProcess = null; + } + + if ( m_currentPostProcess == null && highestReference != null && highestReference != m_camera ) + { + AmplifyMotionPostProcess[] runtimes = gameObject.GetComponents(); + if ( runtimes != null && runtimes.Length > 0 ) + { + for ( int i = 0; i < runtimes.Length; i++ ) + DestroyImmediate( runtimes[ i ] ); + } + m_currentPostProcess = highestReference.gameObject.AddComponent(); + m_currentPostProcess.Instance = this; + } + } + + void LateUpdate() + { + if ( m_baseCamera.AutoStep ) + { + float delta = Application.isPlaying ? Time.deltaTime : Time.fixedDeltaTime; + float fixedDelta = Time.fixedDeltaTime; + + m_deltaTime = ( delta > float.Epsilon ) ? delta : m_deltaTime; + m_fixedDeltaTime = ( delta > float.Epsilon ) ? fixedDelta : m_fixedDeltaTime; + } + + QualitySteps = Mathf.Clamp( QualitySteps, 0, 16 ); + MotionScale = Mathf.Max( MotionScale, 0 ); + MinVelocity = Mathf.Min( MinVelocity, MaxVelocity ); + DepthThreshold = Mathf.Max( DepthThreshold, 0 ); + + UpdatePostProcess(); + } + + public void StopAutoStep() + { + foreach ( AmplifyMotionCamera cam in m_linkedCameras.Values ) + cam.StopAutoStep(); + } + + public void StartAutoStep() + { + foreach ( AmplifyMotionCamera cam in m_linkedCameras.Values ) + cam.StartAutoStep(); + } + + public void Step( float delta ) + { + m_deltaTime = delta; + m_fixedDeltaTime = delta; + foreach ( AmplifyMotionCamera cam in m_linkedCameras.Values ) + cam.Step(); + } + + void UpdateLinkedCameras() + { + Dictionary.KeyCollection keys = m_linkedCameras.Keys; + Dictionary.ValueCollection values = m_linkedCameras.Values; + + if ( m_linkedCameraKeys == null || keys.Count != m_linkedCameraKeys.Length ) + m_linkedCameraKeys = new Camera[ keys.Count ]; + + if ( m_linkedCameraValues == null || values.Count != m_linkedCameraValues.Length ) + m_linkedCameraValues = new AmplifyMotionCamera[ values.Count ]; + + keys.CopyTo( m_linkedCameraKeys, 0 ); + values.CopyTo( m_linkedCameraValues, 0 ); + + m_linkedCamerasChanged = false; + } + + void FixedUpdate() + { + if ( m_camera.enabled ) + { + if ( m_linkedCamerasChanged ) + UpdateLinkedCameras(); + + #if !UNITY_4 + m_fixedUpdateCB.Clear(); + #endif + + for ( int i = 0; i < m_linkedCameraValues.Length; i++ ) + { + if ( m_linkedCameraValues[ i ] != null && m_linkedCameraValues[ i ].isActiveAndEnabled ) + { + #if UNITY_4 + m_linkedCameraValues[ i ].FixedUpdateTransform(); + #else + m_linkedCameraValues[ i ].FixedUpdateTransform( m_fixedUpdateCB ); + #endif + } + } + } + } + + void OnPreRender() + { + if ( m_camera.enabled && ( Time.frameCount == 1 || Mathf.Abs( Time.deltaTime ) > float.Epsilon ) ) + { + if ( m_linkedCamerasChanged ) + UpdateLinkedCameras(); + + #if !UNITY_4 + m_updateCB.Clear(); + #endif + + for ( int i = 0; i < m_linkedCameraValues.Length; i++ ) + { + if ( m_linkedCameraValues[ i ] != null && m_linkedCameraValues[ i ].isActiveAndEnabled ) + { + #if UNITY_4 + m_linkedCameraValues[ i ].UpdateTransform(); + #else + m_linkedCameraValues[ i ].UpdateTransform( m_updateCB ); + #endif + } + } + } + } + +#if UNITY_4 + void RenderReprojectionVectors( RenderTexture destination, float scale ) + { + Shader.SetGlobalMatrix( "_AM_MATRIX_CURR_REPROJ", m_baseCamera.PrevViewProjMatrix * m_baseCamera.InvViewProjMatrix ); + Shader.SetGlobalFloat( "_AM_MOTION_SCALE", scale ); + + Graphics.Blit( m_dummyTex, destination, m_reprojectionMaterial ); + } +#else + void RenderReprojectionVectors( CommandBuffer commandBuffer, RenderTexture destination, float scale ) + { + commandBuffer.SetGlobalMatrix( "_AM_MATRIX_CURR_REPROJ", m_baseCamera.PrevViewProjMatrix * m_baseCamera.InvViewProjMatrix ); + commandBuffer.SetGlobalFloat( "_AM_MOTION_SCALE", scale ); + + RenderTexture dummy = null; + commandBuffer.Blit( new RenderTargetIdentifier( dummy ), destination, m_reprojectionMaterial ); + } +#endif + + public static void DiscardContents( RenderTexture rtex ) + { + #if !( UNITY_WP8 || UNITY_WP8_1 || UNITY_WSA ) // why?.. + rtex.DiscardContents(); + #endif + } + + void OnPostRender() + { + bool qualityChanged = ( QualityLevel != m_qualityLevel ); + if ( qualityChanged ) + { + CreateMaterials(); + m_qualityLevel = QualityLevel; + } + UpdateRenderTextures( qualityChanged ); + + ResetObjectId(); + + #if UNITY_4 + RenderBuffer prevColor = Graphics.activeColorBuffer; + RenderBuffer prevDepth = Graphics.activeDepthBuffer; + #endif + bool cameraMotion = ( CameraMotionMult > float.Epsilon ); + bool clearColor = !cameraMotion || m_starting; + + float rcpDepthThreshold = ( DepthThreshold > float.Epsilon ) ? 1.0f / DepthThreshold : float.MaxValue; + + m_motionScaleNorm = ( m_deltaTime >= float.Epsilon ) ? MotionScale * ( 1.0f / m_deltaTime ) : 0; + m_fixedMotionScaleNorm = ( m_fixedDeltaTime >= float.Epsilon ) ? MotionScale * ( 1.0f / m_fixedDeltaTime ) : 0; + + float objectScale = !m_starting ? m_motionScaleNorm : 0; + float objectFixedScale = !m_starting ? m_fixedMotionScaleNorm : 0; + + DiscardContents( m_motionRT ); + + #if UNITY_4 + Graphics.SetRenderTarget( m_motionRT ); + GL.Clear( true, clearColor, Color.black ); + + Shader.SetGlobalFloat( "_AM_MIN_VELOCITY", MinVelocity ); + Shader.SetGlobalFloat( "_AM_MAX_VELOCITY", MaxVelocity ); + Shader.SetGlobalFloat( "_AM_RCP_TOTAL_VELOCITY", 1.0f / ( MaxVelocity - MinVelocity ) ); + Shader.SetGlobalVector( "_AM_DEPTH_THRESHOLD", new Vector2( DepthThreshold, rcpDepthThreshold ) ); + #else + m_updateCB.Clear(); + m_renderCB.Clear(); + + m_renderCB.SetGlobalFloat( "_AM_MIN_VELOCITY", MinVelocity ); + m_renderCB.SetGlobalFloat( "_AM_MAX_VELOCITY", MaxVelocity ); + m_renderCB.SetGlobalFloat( "_AM_RCP_TOTAL_VELOCITY", 1.0f / ( MaxVelocity - MinVelocity ) ); + m_renderCB.SetGlobalVector( "_AM_DEPTH_THRESHOLD", new Vector2( DepthThreshold, rcpDepthThreshold ) ); + + m_renderCB.SetRenderTarget( m_motionRT ); + m_renderCB.ClearRenderTarget( true, clearColor, Color.black ); + #endif + + if ( cameraMotion ) + { + float cameraMotionScaleNorm = ( m_deltaTime >= float.Epsilon ) ? MotionScale * CameraMotionMult * ( 1.0f / m_deltaTime ) : 0; + float cameraScale = !m_starting ? cameraMotionScaleNorm : 0; + + #if UNITY_4 + RenderReprojectionVectors( m_motionRT, cameraScale ); + #else + RenderReprojectionVectors( m_renderCB, m_motionRT, cameraScale ); + #endif + } + + #if UNITY_4 + m_baseCamera.RenderVectors( objectScale, objectFixedScale, QualityLevel ); + #else + // base camera + m_baseCamera.RenderVectors( m_renderCB, objectScale, objectFixedScale, QualityLevel ); + + // overlay cameras + for ( int i = 0; i < m_linkedCameraValues.Length; i++ ) + { + AmplifyMotionCamera cam = m_linkedCameraValues[ i ]; + if ( cam != null && cam.Overlay && cam.isActiveAndEnabled ) + m_linkedCameraValues[ i ].RenderVectors( m_renderCB, objectScale, objectFixedScale, QualityLevel ); + } + #endif + + m_starting = false; + + #if UNITY_4 + Graphics.SetRenderTarget( prevColor, prevDepth ); + #endif + } + + void ApplyMotionBlur( RenderTexture source, RenderTexture destination, Vector4 blurStep ) + { + bool mobile = ( QualityLevel == AmplifyMotion.Quality.Mobile ); + int pass = ( int ) QualityLevel; + + RenderTexture depthRT = null; + if ( mobile ) + { + depthRT = RenderTexture.GetTemporary( m_width, m_height, 0, RenderTextureFormat.ARGB32 ); + depthRT.name = "AM-DepthTemp"; + depthRT.wrapMode = TextureWrapMode.Clamp; + depthRT.filterMode = FilterMode.Point; + } + + RenderTexture combinedRT = RenderTexture.GetTemporary( m_width, m_height, 0, source.format ); + combinedRT.name = "AM-CombinedTemp"; + combinedRT.wrapMode = TextureWrapMode.Clamp; + combinedRT.filterMode = FilterMode.Point; + + DiscardContents( combinedRT ); + m_combineMaterial.SetTexture( "_MotionTex", m_motionRT ); + source.filterMode = FilterMode.Point; + Graphics.Blit( source, combinedRT, m_combineMaterial, 0 ); + + m_blurMaterial.SetTexture( "_MotionTex", m_motionRT ); + if ( mobile ) + { + Graphics.Blit( null, depthRT, m_depthMaterial, 0 ); + m_blurMaterial.SetTexture( "_DepthTex", depthRT ); + } + + if ( QualitySteps > 1 ) + { + RenderTexture temp = RenderTexture.GetTemporary( m_width, m_height, 0, source.format ); + temp.name = "AM-CombinedTemp2"; + temp.filterMode = FilterMode.Point; + + float step = 1.0f / QualitySteps; + float scale = 1.0f; + RenderTexture src = combinedRT; + RenderTexture dst = temp; + + for ( int i = 0; i < QualitySteps; i++ ) + { + if ( dst != destination ) + DiscardContents( dst ); + + m_blurMaterial.SetVector( "_AM_BLUR_STEP", blurStep * scale ); + Graphics.Blit( src, dst, m_blurMaterial, pass ); + + if ( i < QualitySteps - 2 ) + { + RenderTexture tmp = dst; + dst = src; + src = tmp; + } + else + { + src = dst; + dst = destination; + } + scale -= step; + } + + RenderTexture.ReleaseTemporary( temp ); + } + else + { + m_blurMaterial.SetVector( "_AM_BLUR_STEP", blurStep ); + Graphics.Blit( combinedRT, destination, m_blurMaterial, pass ); + } + + if ( mobile ) + { + // we need the full res here + m_combineMaterial.SetTexture( "_MotionTex", m_motionRT ); + Graphics.Blit( source, destination, m_combineMaterial, 1 ); + } + + RenderTexture.ReleaseTemporary( combinedRT ); + if ( depthRT != null ) + RenderTexture.ReleaseTemporary( depthRT ); + } + + void OnRenderImage( RenderTexture source, RenderTexture destination ) + { + if ( m_currentPostProcess == null ) + PostProcess( source, destination ); + else + Graphics.Blit( source, destination ); + } + + public void PostProcess( RenderTexture source, RenderTexture destination ) + { + Vector4 blurStep = Vector4.zero; + blurStep.x = MaxVelocity / 1000.0f; + blurStep.y = MaxVelocity / 1000.0f; + + RenderTexture dilatedRT = null; + if ( QualitySettings.antiAliasing > 1 ) + { + dilatedRT = RenderTexture.GetTemporary( m_width, m_height, 0, RenderTextureFormat.ARGB32, RenderTextureReadWrite.Linear ); + dilatedRT.name = "AM-DilatedTemp"; + dilatedRT.filterMode = FilterMode.Point; + + m_dilationMaterial.SetTexture( "_MotionTex", m_motionRT ); + Graphics.Blit( m_motionRT, dilatedRT, m_dilationMaterial, 0 ); + m_dilationMaterial.SetTexture( "_MotionTex", dilatedRT ); + Graphics.Blit( dilatedRT, m_motionRT, m_dilationMaterial, 1 ); + } + + if ( DebugMode ) + { + m_debugMaterial.SetTexture( "_MotionTex", m_motionRT ); + Graphics.Blit( source, destination, m_debugMaterial ); + } + else + { + ApplyMotionBlur( source, destination, blurStep ); + } + + if ( dilatedRT != null ) + RenderTexture.ReleaseTemporary( dilatedRT ); + } + +#if TRIAL + void OnGUI() + { + GUI.DrawTexture( new Rect( 15, Screen.height - m_watermark.height - 12, m_watermark.width, m_watermark.height ), m_watermark ); + } +#endif + + //void OnGUI() + //{ + // GUI.color = Color.black; + // GUILayout.BeginHorizontal(); + // GUILayout.Space( 300 ); + // GUILayout.BeginVertical(); + // GUILayout.Label( "GPU / RT / SM3 => " + m_canUseGPU + " / " + SystemInfo.supportsRenderTextures + " / " + ( SystemInfo.graphicsShaderLevel >= 30 ) ); + // GUILayout.Label( "TEX.RHalf => " + SystemInfo.SupportsTextureFormat( TextureFormat.RHalf ) ); + // GUILayout.Label( "TEX.RGHalf => " + SystemInfo.SupportsTextureFormat( TextureFormat.RGHalf ) ); + // GUILayout.Label( "TEX.RGBAHalf => " + SystemInfo.SupportsTextureFormat( TextureFormat.RGBAHalf ) ); + // GUILayout.Label( "RT.RFloat => " + SystemInfo.SupportsRenderTextureFormat( RenderTextureFormat.RFloat ) ); + // GUILayout.Label( "RT.ARGBFloat => " + SystemInfo.SupportsRenderTextureFormat( RenderTextureFormat.ARGBFloat ) ); + // GUILayout.EndVertical(); + // GUILayout.EndHorizontal(); + //} +} diff --git a/Assets/Cinematic Effects/MotionBlur/Plugins/AmplifyMotionBase.cs.meta b/Assets/Cinematic Effects/MotionBlur/Plugins/AmplifyMotionBase.cs.meta new file mode 100644 index 0000000..fb79157 --- /dev/null +++ b/Assets/Cinematic Effects/MotionBlur/Plugins/AmplifyMotionBase.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 8deec7bec0fc2284e96c09a92987d61f +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/MotionBlur/Plugins/AmplifyMotionCamera.cs b/Assets/Cinematic Effects/MotionBlur/Plugins/AmplifyMotionCamera.cs new file mode 100644 index 0000000..874c73f --- /dev/null +++ b/Assets/Cinematic Effects/MotionBlur/Plugins/AmplifyMotionCamera.cs @@ -0,0 +1,318 @@ +// Amplify Motion - Full-scene Motion Blur for Unity Pro +// Copyright (c) Amplify Creations, Lda + +#if UNITY_4_0 || UNITY_4_1 || UNITY_4_2 || UNITY_4_3 || UNITY_4_4 || UNITY_4_5 || UNITY_4_6 || UNITY_4_7 || UNITY_4_8 || UNITY_4_9 +#define UNITY_4 +#endif +#if UNITY_5_0 || UNITY_5_1 || UNITY_5_2 || UNITY_5_3 || UNITY_5_4 || UNITY_5_5 || UNITY_5_6 || UNITY_5_7 || UNITY_5_8 || UNITY_5_9 +#define UNITY_5 +#endif + +using System; +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +#if !UNITY_4 +using UnityEngine.Rendering; +#endif + +[AddComponentMenu( "" )] +[RequireComponent( typeof( Camera ) )] +public class AmplifyMotionCamera : MonoBehaviour +{ + internal AmplifyMotionEffectBase Instance = null; + + internal Matrix4x4 PrevViewProjMatrix; + internal Matrix4x4 ViewProjMatrix; + internal Matrix4x4 InvViewProjMatrix; + + internal Matrix4x4 PrevViewProjMatrixRT; + internal Matrix4x4 ViewProjMatrixRT; + + internal Transform Transform; + + private bool m_linked = false; + private bool m_initialized = false; + private bool m_starting = true; + + private bool m_autoStep = true; + private bool m_step = false; + private bool m_overlay = false; + private Camera m_camera; + + public bool Initialized { get { return m_initialized; } } + public bool AutoStep { get { return m_autoStep; } } + public bool Overlay { get { return m_overlay; } } + public Camera Camera { get { return m_camera; } } + + private int m_prevFrameCount = 0; + + private HashSet m_affectedObjectsTable = new HashSet(); + private AmplifyMotionObjectBase[] m_affectedObjects = null; + private bool m_affectedObjectsChanged = true; + + public void RegisterObject( AmplifyMotionObjectBase obj ) + { + m_affectedObjectsTable.Add( obj ); + m_affectedObjectsChanged = true; + } + + public void UnregisterObject( AmplifyMotionObjectBase obj ) + { + m_affectedObjectsTable.Remove( obj ); + m_affectedObjectsChanged = true; + } + + void UpdateAffectedObjects() + { + if ( m_affectedObjects == null || m_affectedObjectsTable.Count != m_affectedObjects.Length ) + m_affectedObjects = new AmplifyMotionObjectBase[ m_affectedObjectsTable.Count ]; + + m_affectedObjectsTable.CopyTo( m_affectedObjects ); + + m_affectedObjectsChanged = false; + } + + public void LinkTo( AmplifyMotionEffectBase instance, bool overlay ) + { + Instance = instance; + + m_camera = GetComponent(); + m_camera.depthTextureMode |= DepthTextureMode.Depth; + + m_overlay = overlay; + m_linked = true; + } + + public void Initialize() + { + m_step = false; + UpdateMatrices(); + m_initialized = true; + } + + void Awake() + { + Transform = transform; + } + + void OnEnable() + { + AmplifyMotionEffectBase.RegisterCamera( this ); + } + + void OnDisable() + { + m_initialized = false; + AmplifyMotionEffectBase.UnregisterCamera( this ); + } + + void OnDestroy() + { + if ( Instance != null ) + Instance.RemoveCamera( m_camera ); + } + + public void StopAutoStep() + { + if ( m_autoStep ) + { + m_autoStep = false; + m_step = true; + } + } + + public void StartAutoStep() + { + m_autoStep = true; + } + + public void Step() + { + m_step = true; + } + + void Update() + { + if ( !m_linked || !Instance.isActiveAndEnabled ) + return; + + if ( !m_initialized ) + Initialize(); + + if ( ( m_camera.depthTextureMode & DepthTextureMode.Depth ) == 0 ) + m_camera.depthTextureMode |= DepthTextureMode.Depth; + } + + void UpdateMatrices() + { + if ( !m_starting ) + { + PrevViewProjMatrix = ViewProjMatrix; + PrevViewProjMatrixRT = ViewProjMatrixRT; + } + + Matrix4x4 view = m_camera.worldToCameraMatrix; + Matrix4x4 proj = GL.GetGPUProjectionMatrix( m_camera.projectionMatrix, false ); + ViewProjMatrix = proj * view; + InvViewProjMatrix = Matrix4x4.Inverse( ViewProjMatrix ); + + Matrix4x4 projRT = GL.GetGPUProjectionMatrix( m_camera.projectionMatrix, true ); + ViewProjMatrixRT = projRT * view; + + if ( m_starting ) + { + PrevViewProjMatrix = ViewProjMatrix; + PrevViewProjMatrixRT = ViewProjMatrixRT; + } + } + +#if UNITY_4 + public void FixedUpdateTransform() +#else + public void FixedUpdateTransform( CommandBuffer updateCB ) +#endif + { + if ( !m_initialized ) + Initialize(); + + if ( m_affectedObjectsChanged ) + UpdateAffectedObjects(); + + for ( int i = 0; i < m_affectedObjects.Length; i++ ) + { + if ( m_affectedObjects[ i ].FixedStep ) + { + #if UNITY_4 + m_affectedObjects[ i ].OnUpdateTransform( m_camera, m_starting ); + #else + m_affectedObjects[ i ].OnUpdateTransform( m_camera, updateCB, m_starting ); + #endif + } + } + } + +#if UNITY_4 + public void UpdateTransform() +#else + public void UpdateTransform( CommandBuffer updateCB ) +#endif + { + if ( !m_initialized ) + Initialize(); + + if ( Time.frameCount > m_prevFrameCount && ( m_autoStep || m_step ) ) + { + UpdateMatrices(); + + if ( m_affectedObjectsChanged ) + UpdateAffectedObjects(); + + for ( int i = 0; i < m_affectedObjects.Length; i++ ) + { + if ( !m_affectedObjects[ i ].FixedStep ) + { + #if UNITY_4 + m_affectedObjects[ i ].OnUpdateTransform( m_camera, m_starting ); + #else + m_affectedObjects[ i ].OnUpdateTransform( m_camera, updateCB, m_starting ); + #endif + + } + } + + m_starting = false; + m_step = false; + + m_prevFrameCount = Time.frameCount; + } + } + +#if UNITY_4 + public void RenderVectors( float scale, float fixedScale, AmplifyMotion.Quality quality ) +#else + public void RenderVectors( CommandBuffer renderCB, float scale, float fixedScale, AmplifyMotion.Quality quality ) +#endif + { + if ( !m_initialized ) + Initialize(); + + // For some reason Unity's own values weren't working correctly on Windows/OpenGL + float near = m_camera.nearClipPlane; + float far = m_camera.farClipPlane; + Vector4 zparam; + + if ( AmplifyMotionEffectBase.IsD3D ) + { + zparam.x = 1.0f - far / near; + zparam.y = far / near; + } + else + { + // OpenGL + zparam.x = ( 1.0f - far / near ) / 2.0f; + zparam.y = ( 1.0f + far / near ) / 2.0f; + } + + zparam.z = zparam.x / far; + zparam.w = zparam.y / far; + + Shader.SetGlobalVector( "_AM_ZBUFFER_PARAMS", zparam ); + + if ( m_affectedObjectsChanged ) + UpdateAffectedObjects(); + + for ( int i = 0; i < m_affectedObjects.Length; i++ ) + { + // don't render objects excluded via camera culling mask + if ( ( m_camera.cullingMask & ( 1 << m_affectedObjects[ i ].gameObject.layer ) ) != 0 ) + { + #if UNITY_4 + m_affectedObjects[ i ].OnRenderVectors( m_camera, m_affectedObjects[ i ].FixedStep ? fixedScale : scale, quality ); + #else + m_affectedObjects[ i ].OnRenderVectors( m_camera, renderCB, m_affectedObjects[ i ].FixedStep ? fixedScale : scale, quality ); + #endif + } + } + } + +#if UNITY_4 + void OnPostRender() + { + if ( !m_linked || !Instance.isActiveAndEnabled ) + return; + + if ( !m_initialized ) + Initialize(); + + if ( m_overlay ) + { + + RenderTexture prevRT = RenderTexture.active; + + Graphics.SetRenderTarget( Instance.MotionRenderTexture ); + RenderVectors( Instance.MotionScaleNorm, Instance.FixedMotionScaleNorm, Instance.QualityLevel ); + + RenderTexture.active = prevRT; + } + } +#endif + + void OnGUI() + { + if ( !Application.isEditor ) + return; + + if ( !m_linked || !Instance.isActiveAndEnabled ) + return; + + if ( !m_initialized ) + Initialize(); + + if ( m_affectedObjectsChanged ) + UpdateAffectedObjects(); + + for ( int i = 0; i < m_affectedObjects.Length; i++ ) + m_affectedObjects[ i ].OnRenderDebugHUD( m_camera ); + } +} diff --git a/Assets/Cinematic Effects/MotionBlur/Plugins/AmplifyMotionCamera.cs.meta b/Assets/Cinematic Effects/MotionBlur/Plugins/AmplifyMotionCamera.cs.meta new file mode 100644 index 0000000..7cdf87b --- /dev/null +++ b/Assets/Cinematic Effects/MotionBlur/Plugins/AmplifyMotionCamera.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 32f3679b48c5ac84f913fe16c3ffb43a +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/MotionBlur/Plugins/AmplifyMotionEffect.cs b/Assets/Cinematic Effects/MotionBlur/Plugins/AmplifyMotionEffect.cs new file mode 100644 index 0000000..8259f05 --- /dev/null +++ b/Assets/Cinematic Effects/MotionBlur/Plugins/AmplifyMotionEffect.cs @@ -0,0 +1,13 @@ +// Amplify Motion - Full-scene Motion Blur for Unity Pro +// Copyright (c) Amplify Creations, Lda + +using System; +using UnityEngine; + +[RequireComponent( typeof( Camera ) )] +[AddComponentMenu( "Image Effects/Amplify Motion" )] +public class AmplifyMotionEffect : AmplifyMotionEffectBase +{ + public static new AmplifyMotionEffect FirstInstance { get { return ( AmplifyMotionEffect ) AmplifyMotionEffectBase.FirstInstance; } } + public static new AmplifyMotionEffect Instance { get { return ( AmplifyMotionEffect ) AmplifyMotionEffectBase.Instance; } } +} diff --git a/Assets/Cinematic Effects/MotionBlur/Plugins/AmplifyMotionEffect.cs.meta b/Assets/Cinematic Effects/MotionBlur/Plugins/AmplifyMotionEffect.cs.meta new file mode 100644 index 0000000..27f08b4 --- /dev/null +++ b/Assets/Cinematic Effects/MotionBlur/Plugins/AmplifyMotionEffect.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 390397f02bff7644ab045efd81d0d720 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 0ea3c819440ae8346ae765cd2a7d95cc, type: 3} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/MotionBlur/Plugins/AmplifyMotionObject.cs b/Assets/Cinematic Effects/MotionBlur/Plugins/AmplifyMotionObject.cs new file mode 100644 index 0000000..9005615 --- /dev/null +++ b/Assets/Cinematic Effects/MotionBlur/Plugins/AmplifyMotionObject.cs @@ -0,0 +1,10 @@ +// Amplify Motion - Full-scene Motion Blur for Unity Pro +// Copyright (c) Amplify Creations, Lda + +using System; +using UnityEngine; + +[AddComponentMenu( "Image Effects/Amplify Motion Object" )] +public class AmplifyMotionObject : AmplifyMotionObjectBase +{ +} diff --git a/Assets/Cinematic Effects/MotionBlur/Plugins/AmplifyMotionObject.cs.meta b/Assets/Cinematic Effects/MotionBlur/Plugins/AmplifyMotionObject.cs.meta new file mode 100644 index 0000000..ddf4146 --- /dev/null +++ b/Assets/Cinematic Effects/MotionBlur/Plugins/AmplifyMotionObject.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 3be5e33915e952b4cac8186b1a6f8f3f +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: be11958c9498dd048baecca8002f8212, type: 3} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/MotionBlur/Plugins/AmplifyMotionObjectBase.cs b/Assets/Cinematic Effects/MotionBlur/Plugins/AmplifyMotionObjectBase.cs new file mode 100644 index 0000000..3b7b98f --- /dev/null +++ b/Assets/Cinematic Effects/MotionBlur/Plugins/AmplifyMotionObjectBase.cs @@ -0,0 +1,371 @@ +// Amplify Motion - Full-scene Motion Blur for Unity Pro +// Copyright (c) Amplify Creations, Lda + +#if UNITY_4_0 || UNITY_4_1 || UNITY_4_2 || UNITY_4_3 || UNITY_4_4 || UNITY_4_5 || UNITY_4_6 || UNITY_4_7 || UNITY_4_8 || UNITY_4_9 +#define UNITY_4 +#endif +#if UNITY_5_0 || UNITY_5_1 || UNITY_5_2 || UNITY_5_3 || UNITY_5_4 || UNITY_5_5 || UNITY_5_6 || UNITY_5_7 || UNITY_5_8 || UNITY_5_9 +#define UNITY_5 +#endif +#if UNITY_4 || UNITY_5_0 || UNITY_5_1 || UNITY_5_2 +#define UNITY_PRE_5_3 +#endif + +using System; +using System.Collections.Generic; +using UnityEngine; +#if !UNITY_4 +using UnityEngine.Rendering; +#endif + +namespace AmplifyMotion +{ + +public enum ObjectType +{ + None, + Solid, + Skinned, + Cloth, +#if !UNITY_PRE_5_3 + Particle +#endif +} + +[Serializable] +internal abstract class MotionState +{ + protected struct MaterialDesc + { + public Material material; + #if !UNITY_4 + public MaterialPropertyBlock propertyBlock; + #endif + public bool coverage; + public bool cutoff; + } + + public const int AsyncUpdateTimeout = 100; + + protected bool m_error; + protected bool m_initialized; + protected Transform m_transform; + + protected AmplifyMotionCamera m_owner; + protected AmplifyMotionObjectBase m_obj; + + public AmplifyMotionCamera Owner { get { return m_owner; } } + public bool Initialized { get { return m_initialized; } } + public bool Error { get { return m_error; } } + + public MotionState( AmplifyMotionCamera owner, AmplifyMotionObjectBase obj ) + { + m_error = false; + m_initialized = false; + + m_owner = owner; + m_obj = obj; + m_transform = obj.transform; + } + + internal virtual void Initialize() { m_initialized = true; } + internal virtual void Shutdown() {} + + internal virtual void AsyncUpdate() {} +#if UNITY_4 + internal abstract void UpdateTransform( bool starting ); + internal virtual void RenderVectors( Camera camera, float scale, AmplifyMotion.Quality quality ) {} +#else + internal abstract void UpdateTransform( CommandBuffer updateCB, bool starting ); + internal virtual void RenderVectors( Camera camera, CommandBuffer renderCB, float scale, AmplifyMotion.Quality quality ) {} +#endif + internal virtual void RenderDebugHUD() {} + + private static HashSet m_materialWarnings = new HashSet(); + + protected MaterialDesc[] ProcessSharedMaterials( Material[] mats ) + { + MaterialDesc[] matsDesc = new MaterialDesc [ mats.Length ]; + for ( int i = 0; i < mats.Length; i++ ) + { + matsDesc[ i ].material = mats[ i ]; + bool legacyCoverage = ( mats[ i ].GetTag( "RenderType", false ) == "TransparentCutout" ); + #if UNITY_4 + bool isCoverage = legacyCoverage; + matsDesc[ i ].coverage = mats[ i ].HasProperty( "_MainTex" ) && isCoverage; + #else + bool isCoverage = legacyCoverage || mats[ i ].IsKeywordEnabled( "_ALPHATEST_ON" ); + matsDesc[ i ].propertyBlock = new MaterialPropertyBlock(); + matsDesc[ i ].coverage = mats[ i ].HasProperty( "_MainTex" ) && isCoverage; + #endif + matsDesc[ i ].cutoff = mats[ i ].HasProperty( "_Cutoff" ); + + if ( isCoverage && !matsDesc[ i ].coverage && !m_materialWarnings.Contains( matsDesc[ i ].material ) ) + { + Debug.LogWarning( "[AmplifyMotion] TransparentCutout material \"" + matsDesc[ i ].material.name + "\" {" + matsDesc[ i ].material.shader.name + "} not using _MainTex standard property." ); + m_materialWarnings.Add( matsDesc[ i ].material ); + } + } + return matsDesc; + } + + internal static bool VectorChanged( Vector3 a, Vector3 b ) + { + return Vector3.SqrMagnitude( a - b ) > 0.0f; + } + + internal static bool RotationChanged( Quaternion a, Quaternion b ) + { + Vector4 diff = new Vector4( a.x - b.x, a.y - b.y, a.z - b.z, a.w - b.w ); + return Vector4.SqrMagnitude( diff ) > 0.0f; + } + + internal static void MulPoint4x4_XYZW( ref Vector4 result, ref Matrix4x4 mat, Vector4 vec ) + { + result.x = mat.m00 * vec.x + mat.m01 * vec.y + mat.m02 * vec.z + mat.m03 * vec.w; + result.y = mat.m10 * vec.x + mat.m11 * vec.y + mat.m12 * vec.z + mat.m13 * vec.w; + result.z = mat.m20 * vec.x + mat.m21 * vec.y + mat.m22 * vec.z + mat.m23 * vec.w; + result.w = mat.m30 * vec.x + mat.m31 * vec.y + mat.m32 * vec.z + mat.m33 * vec.w; + } + + internal static void MulPoint3x4_XYZ( ref Vector3 result, ref Matrix4x4 mat, Vector4 vec ) + { + result.x = mat.m00 * vec.x + mat.m01 * vec.y + mat.m02 * vec.z + mat.m03; + result.y = mat.m10 * vec.x + mat.m11 * vec.y + mat.m12 * vec.z + mat.m13; + result.z = mat.m20 * vec.x + mat.m21 * vec.y + mat.m22 * vec.z + mat.m23; + } + + internal static void MulPoint3x4_XYZW( ref Vector3 result, ref Matrix4x4 mat, Vector4 vec ) + { + result.x = mat.m00 * vec.x + mat.m01 * vec.y + mat.m02 * vec.z + mat.m03 * vec.w; + result.y = mat.m10 * vec.x + mat.m11 * vec.y + mat.m12 * vec.z + mat.m13 * vec.w; + result.z = mat.m20 * vec.x + mat.m21 * vec.y + mat.m22 * vec.z + mat.m23 * vec.w; + } + + internal static void MulAddPoint3x4_XYZW( ref Vector3 result, ref Matrix4x4 mat, Vector4 vec ) + { + result.x += mat.m00 * vec.x + mat.m01 * vec.y + mat.m02 * vec.z + mat.m03 * vec.w; + result.y += mat.m10 * vec.x + mat.m11 * vec.y + mat.m12 * vec.z + mat.m13 * vec.w; + result.z += mat.m20 * vec.x + mat.m21 * vec.y + mat.m22 * vec.z + mat.m23 * vec.w; + } +} +} + +[AddComponentMenu( "" )] +public class AmplifyMotionObjectBase : MonoBehaviour +{ + public enum MinMaxCurveState + { + Scalar = 0, + Curve = 1, + TwoCurves = 2, + TwoScalars = 3 + } + + internal static bool ApplyToChildren = true; + [SerializeField] private bool m_applyToChildren = ApplyToChildren; + + private AmplifyMotion.ObjectType m_type = AmplifyMotion.ObjectType.None; + private Dictionary m_states = new Dictionary(); + + private bool m_fixedStep = false; + private int m_objectId = 0; + + internal bool FixedStep { get { return m_fixedStep; } } + internal int ObjectId { get { return m_objectId; } } + + public AmplifyMotion.ObjectType Type { get { return m_type; } } + + internal void RegisterCamera( AmplifyMotionCamera camera ) + { + Camera actual = camera.GetComponent(); + if ( ( actual.cullingMask & ( 1 << gameObject.layer ) ) != 0 && !m_states.ContainsKey( actual ) ) + { + AmplifyMotion.MotionState state = null; + switch ( m_type ) + { + case AmplifyMotion.ObjectType.Solid: + state = new AmplifyMotion.SolidState( camera, this ); break; + case AmplifyMotion.ObjectType.Skinned: + state = new AmplifyMotion.SkinnedState( camera, this ); break; + case AmplifyMotion.ObjectType.Cloth: + state = new AmplifyMotion.ClothState( camera, this ); break; + #if !UNITY_PRE_5_3 + case AmplifyMotion.ObjectType.Particle: + state = new AmplifyMotion.ParticleState( camera, this ); break; + #endif + default: + throw new Exception( "[AmplifyMotion] Invalid object type." ); + } + + camera.RegisterObject( this ); + + m_states.Add( actual, state ); + } + } + + internal void UnregisterCamera( AmplifyMotionCamera camera ) + { + AmplifyMotion.MotionState state; + Camera actual = camera.GetComponent(); + if ( m_states.TryGetValue( actual, out state ) ) + { + camera.UnregisterObject( this ); + + if ( m_states.TryGetValue( actual, out state ) ) + state.Shutdown(); + + m_states.Remove( actual ); + } + } + + bool InitializeType() + { + Renderer renderer = GetComponent(); + if ( AmplifyMotionEffectBase.CanRegister( gameObject, false ) ) + { + #if !UNITY_PRE_5_3 + ParticleSystem particleRenderer = GetComponent(); + if ( particleRenderer != null ) + { + m_type = AmplifyMotion.ObjectType.Particle; + AmplifyMotionEffectBase.RegisterObject( this ); + } + else + #endif + if ( renderer != null ) + { + // At this point, Renderer is guaranteed to be one of the following + if ( renderer.GetType() == typeof( MeshRenderer ) ) + m_type = AmplifyMotion.ObjectType.Solid; + #if UNITY_4 + else if ( renderer.GetType() == typeof( ClothRenderer ) ) + m_type = AmplifyMotion.ObjectType.Cloth; + #endif + else if ( renderer.GetType() == typeof( SkinnedMeshRenderer ) ) + { + #if !UNITY_4 + if ( GetComponent() != null ) + m_type = AmplifyMotion.ObjectType.Cloth; + else + #endif + m_type = AmplifyMotion.ObjectType.Skinned; + } + + AmplifyMotionEffectBase.RegisterObject( this ); + } + } + + // No renderer? disable it, it is here just for adding children + return ( renderer != null ); + } + + void OnEnable() + { + bool valid = InitializeType(); + if ( valid ) + { + if ( m_type == AmplifyMotion.ObjectType.Cloth ) + { + #if UNITY_4 + m_fixedStep = true; + #else + m_fixedStep = false; + #endif + } + else if ( m_type == AmplifyMotion.ObjectType.Solid ) + { + Rigidbody rigidbody = GetComponent(); + if ( rigidbody != null && rigidbody.interpolation == RigidbodyInterpolation.None && !rigidbody.isKinematic ) + m_fixedStep = true; + } + } + + if ( m_applyToChildren ) + { + foreach ( Transform child in gameObject.transform ) + AmplifyMotionEffectBase.RegisterRecursivelyS( child.gameObject ); + } + + if ( !valid ) + enabled = false; + } + + void OnDisable() + { + AmplifyMotionEffectBase.UnregisterObject( this ); + } + + void TryInitializeStates() + { + var enumerator = m_states.GetEnumerator(); + while ( enumerator.MoveNext() ) + { + AmplifyMotion.MotionState state = enumerator.Current.Value; + if ( state.Owner.Initialized && !state.Error && !state.Initialized ) + state.Initialize(); + } + } + + void Start() + { + if ( AmplifyMotionEffectBase.Instance != null ) + TryInitializeStates(); + } + + void Update() + { + if ( AmplifyMotionEffectBase.Instance != null ) + TryInitializeStates(); + } + +#if UNITY_4 + internal void OnUpdateTransform( Camera camera, bool starting ) +#else + internal void OnUpdateTransform( Camera camera, CommandBuffer updateCB, bool starting ) +#endif + { + AmplifyMotion.MotionState state; + if ( m_states.TryGetValue( camera, out state ) ) + { + if ( !state.Error ) + { + #if UNITY_4 + state.UpdateTransform( starting ); + #else + state.UpdateTransform( updateCB, starting ); + #endif + } + } + } + +#if UNITY_4 + internal void OnRenderVectors( Camera camera, float scale, AmplifyMotion.Quality quality ) +#else + internal void OnRenderVectors( Camera camera, CommandBuffer renderCB, float scale, AmplifyMotion.Quality quality ) +#endif + { + AmplifyMotion.MotionState state; + if ( m_states.TryGetValue( camera, out state ) ) + { + if ( !state.Error ) + { + #if UNITY_4 + state.RenderVectors( camera, scale, quality ); + #else + state.RenderVectors( camera, renderCB, scale, quality ); + #endif + } + } + } + + internal void OnRenderDebugHUD( Camera camera ) + { + AmplifyMotion.MotionState state; + if ( m_states.TryGetValue( camera, out state ) ) + { + if ( !state.Error ) + state.RenderDebugHUD(); + } + } +} diff --git a/Assets/Cinematic Effects/MotionBlur/Plugins/AmplifyMotionObjectBase.cs.meta b/Assets/Cinematic Effects/MotionBlur/Plugins/AmplifyMotionObjectBase.cs.meta new file mode 100644 index 0000000..839dc99 --- /dev/null +++ b/Assets/Cinematic Effects/MotionBlur/Plugins/AmplifyMotionObjectBase.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: d700ac4720013ea408722e2fce137691 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/MotionBlur/Plugins/AmplifyMotionPostProcess.cs b/Assets/Cinematic Effects/MotionBlur/Plugins/AmplifyMotionPostProcess.cs new file mode 100644 index 0000000..0ff752b --- /dev/null +++ b/Assets/Cinematic Effects/MotionBlur/Plugins/AmplifyMotionPostProcess.cs @@ -0,0 +1,20 @@ +// Amplify Motion - Full-scene Motion Blur for Unity Pro +// Copyright (c) Amplify Creations, Lda + +using System; +using System.Collections.Generic; +using UnityEngine; + +[AddComponentMenu( "" )] +[RequireComponent( typeof( Camera ) )] +sealed public class AmplifyMotionPostProcess : MonoBehaviour +{ + private AmplifyMotionEffectBase m_instance = null; + public AmplifyMotionEffectBase Instance { get { return m_instance; } set { m_instance = value; } } + + void OnRenderImage( RenderTexture source, RenderTexture destination ) + { + if ( m_instance != null ) + m_instance.PostProcess( source, destination ); + } +} diff --git a/Assets/Cinematic Effects/MotionBlur/Plugins/AmplifyMotionPostProcess.cs.meta b/Assets/Cinematic Effects/MotionBlur/Plugins/AmplifyMotionPostProcess.cs.meta new file mode 100644 index 0000000..e47b0ca --- /dev/null +++ b/Assets/Cinematic Effects/MotionBlur/Plugins/AmplifyMotionPostProcess.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 14fbfa86b7161f344b463004a203fcea +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/MotionBlur/Plugins/ClothState.cs b/Assets/Cinematic Effects/MotionBlur/Plugins/ClothState.cs new file mode 100644 index 0000000..43cda78 --- /dev/null +++ b/Assets/Cinematic Effects/MotionBlur/Plugins/ClothState.cs @@ -0,0 +1,293 @@ +// Amplify Motion - Full-scene Motion Blur for Unity Pro +// Copyright (c) Amplify Creations, Lda + +#if UNITY_4_0 || UNITY_4_1 || UNITY_4_2 || UNITY_4_3 || UNITY_4_4 || UNITY_4_5 || UNITY_4_6 || UNITY_4_7 || UNITY_4_8 || UNITY_4_9 +#define UNITY_4 +#endif +#if UNITY_5_0 || UNITY_5_1 || UNITY_5_2 || UNITY_5_3 || UNITY_5_4 || UNITY_5_5 || UNITY_5_6 || UNITY_5_7 || UNITY_5_8 || UNITY_5_9 +#define UNITY_5 +#endif + +using System; +using System.Collections.Generic; +using System.Threading; +using UnityEngine; +using UnityEngine.Profiling; +#if !UNITY_4 +using UnityEngine.Rendering; +#endif + +namespace AmplifyMotion +{ +internal class ClothState : AmplifyMotion.MotionState +{ +#if UNITY_4 + private InteractiveCloth m_cloth; +#else + private Cloth m_cloth; +#endif + private Renderer m_renderer; + + public Matrix4x4 m_prevLocalToWorld; + public Matrix4x4 m_currLocalToWorld; + + private int m_targetVertexCount; + private int[] m_targetRemap; + private Vector3[] m_prevVertices; + private Vector3[] m_currVertices; + + private Mesh m_clonedMesh; + + private MaterialDesc[] m_sharedMaterials; + + private bool m_starting; + private bool m_wasVisible; + + private static HashSet m_uniqueWarnings = new HashSet(); + + public ClothState( AmplifyMotionCamera owner, AmplifyMotionObjectBase obj ) + : base( owner, obj ) + { + #if UNITY_4 + m_cloth = m_obj.GetComponent(); + #else + m_cloth = m_obj.GetComponent(); + #endif + } + + internal override void Initialize() + { + if ( m_cloth.vertices == null ) + { + if ( !m_uniqueWarnings.Contains( m_obj ) ) + { + Debug.LogWarning( "[AmplifyMotion] Invalid " + m_cloth.GetType().Name + " vertices in object " + m_obj.name + ". Skipping." ); + m_uniqueWarnings.Add( m_obj ); + } + m_error = true; + return; + } + + #if UNITY_4 + Mesh clothMesh = m_cloth.mesh; + #else + SkinnedMeshRenderer skinnedRenderer = m_cloth.gameObject.GetComponent(); + Mesh clothMesh = skinnedRenderer.sharedMesh; + #endif + + if ( clothMesh == null || clothMesh.vertices == null || clothMesh.triangles == null ) + { + Debug.LogError( "[AmplifyMotion] Invalid Mesh on Cloth-enabled object " + m_obj.name ); + m_error = true; + return; + } + + base.Initialize(); + + m_renderer = m_cloth.gameObject.GetComponent(); + + int meshVertexCount = clothMesh.vertexCount; + Vector3[] meshVertices = clothMesh.vertices; + Vector2[] meshTexcoords = clothMesh.uv; + int[] meshTriangles = clothMesh.triangles; + + m_targetRemap = new int[ meshVertexCount ]; + + if ( m_cloth.vertices.Length == clothMesh.vertices.Length ) + { + for ( int i = 0; i < meshVertexCount; i++ ) + m_targetRemap[ i ] = i; + } + else + { + // a) May contains duplicated verts, optimization/cleanup is required + Dictionary dict = new Dictionary(); + int original, vertexCount = 0; + + for ( int i = 0; i < meshVertexCount; i++ ) + { + if ( dict.TryGetValue( meshVertices[ i ], out original ) ) + m_targetRemap[ i ] = original; + else + { + m_targetRemap[ i ] = vertexCount; + dict.Add( meshVertices[ i ], vertexCount++ ); + } + } + + // b) Tear is activated, creates extra verts (NOT SUPPORTED, POOL OF VERTS USED, NO ACCESS TO TRIANGLES) + } + + m_targetVertexCount = meshVertexCount; + m_prevVertices = new Vector3[ m_targetVertexCount ]; + m_currVertices = new Vector3[ m_targetVertexCount ]; + + m_clonedMesh = new Mesh(); + m_clonedMesh.vertices = meshVertices; + m_clonedMesh.normals = meshVertices; + m_clonedMesh.uv = meshTexcoords; + m_clonedMesh.triangles = meshTriangles; + + m_sharedMaterials = ProcessSharedMaterials( m_renderer.sharedMaterials ); + + m_wasVisible = false; + } + + internal override void Shutdown() + { + Mesh.Destroy( m_clonedMesh ); + } + +#if UNITY_4 + internal override void UpdateTransform( bool starting ) +#else + internal override void UpdateTransform( CommandBuffer updateCB, bool starting ) +#endif + { + if ( !m_initialized ) + { + Initialize(); + return; + } + + Profiler.BeginSample( "Cloth.Update" ); + + if ( !starting && m_wasVisible ) + m_prevLocalToWorld = m_currLocalToWorld; + + bool isVisible = m_renderer.isVisible; + if ( !m_error && ( isVisible || starting ) ) + { + if ( !starting && m_wasVisible ) + Array.Copy( m_currVertices, m_prevVertices, m_targetVertexCount ); + } + + #if UNITY_4 + m_currLocalToWorld = Matrix4x4.identity; + #else + m_currLocalToWorld = Matrix4x4.TRS( m_transform.position, m_transform.rotation, Vector3.one ); + #endif + + if ( starting || !m_wasVisible ) + m_prevLocalToWorld = m_currLocalToWorld; + + m_starting = starting; + m_wasVisible = isVisible; + + Profiler.EndSample(); + } + +#if UNITY_4 + internal override void RenderVectors( Camera camera, float scale, AmplifyMotion.Quality quality ) + { + if ( m_initialized && !m_error && m_renderer.isVisible ) + { + Profiler.BeginSample( "Cloth.Render" ); + + const float rcp255 = 1 / 255.0f; + bool mask = ( m_owner.Instance.CullingMask & ( 1 << m_obj.gameObject.layer ) ) != 0; + int objectId = mask ? m_owner.Instance.GenerateObjectId( m_obj.gameObject ) : 255; + + Vector3[] clothVertices = m_cloth.vertices; + for ( int i = 0; i < m_targetVertexCount; i++ ) + m_currVertices[ i ] = clothVertices[ m_targetRemap[ i ] ]; + + if ( m_starting || !m_wasVisible ) + Array.Copy( m_currVertices, m_prevVertices, m_targetVertexCount ); + + m_clonedMesh.vertices = m_currVertices; + m_clonedMesh.normals = m_prevVertices; + + Matrix4x4 prevModelViewProj; + if ( m_obj.FixedStep ) + prevModelViewProj = m_owner.PrevViewProjMatrixRT * m_currLocalToWorld; + else + prevModelViewProj = m_owner.PrevViewProjMatrixRT * m_prevLocalToWorld; + + Shader.SetGlobalMatrix( "_AM_MATRIX_PREV_MVP", prevModelViewProj ); + Shader.SetGlobalFloat( "_AM_OBJECT_ID", objectId * rcp255 ); + Shader.SetGlobalFloat( "_AM_MOTION_SCALE", mask ? scale : 0 ); + + int qualityPass = ( quality == AmplifyMotion.Quality.Mobile ) ? 0 : 2; + + for ( int i = 0; i < m_sharedMaterials.Length; i++ ) + { + MaterialDesc matDesc = m_sharedMaterials[ i ]; + int pass = qualityPass + ( matDesc.coverage ? 1 : 0 ); + + if ( matDesc.coverage ) + { + m_owner.Instance.ClothVectorsMaterial.mainTexture = matDesc.material.mainTexture; + if ( matDesc.cutoff ) + m_owner.Instance.ClothVectorsMaterial.SetFloat( "_Cutoff", matDesc.material.GetFloat( "_Cutoff" ) ); + } + + if ( m_owner.Instance.ClothVectorsMaterial.SetPass( pass ) ) + { + #if UNITY_4 + Graphics.DrawMeshNow( m_clonedMesh, Matrix4x4.identity, i ); + #else + Graphics.DrawMeshNow( m_clonedMesh, m_currLocalToWorld, i ); + #endif + } + } + + Profiler.EndSample(); + } + } +#else + internal override void RenderVectors( Camera camera, CommandBuffer renderCB, float scale, AmplifyMotion.Quality quality ) + { + if ( m_initialized && !m_error && m_renderer.isVisible ) + { + Profiler.BeginSample( "Cloth.Render" ); + + const float rcp255 = 1 / 255.0f; + bool mask = ( m_owner.Instance.CullingMask & ( 1 << m_obj.gameObject.layer ) ) != 0; + int objectId = mask ? m_owner.Instance.GenerateObjectId( m_obj.gameObject ) : 255; + + Vector3[] clothVertices = m_cloth.vertices; + for ( int i = 0; i < m_targetVertexCount; i++ ) + m_currVertices[ i ] = clothVertices[ m_targetRemap[ i ] ]; + + if ( m_starting || !m_wasVisible ) + Array.Copy( m_currVertices, m_prevVertices, m_targetVertexCount ); + + m_clonedMesh.vertices = m_currVertices; + m_clonedMesh.normals = m_prevVertices; + + Matrix4x4 prevModelViewProj; + if ( m_obj.FixedStep ) + prevModelViewProj = m_owner.PrevViewProjMatrixRT * m_currLocalToWorld; + else + prevModelViewProj = m_owner.PrevViewProjMatrixRT * m_prevLocalToWorld; + + renderCB.SetGlobalMatrix( "_AM_MATRIX_PREV_MVP", prevModelViewProj ); + renderCB.SetGlobalFloat( "_AM_OBJECT_ID", objectId * rcp255 ); + renderCB.SetGlobalFloat( "_AM_MOTION_SCALE", mask ? scale : 0 ); + + int qualityPass = ( quality == AmplifyMotion.Quality.Mobile ) ? 0 : 2; + + for ( int i = 0; i < m_sharedMaterials.Length; i++ ) + { + MaterialDesc matDesc = m_sharedMaterials[ i ]; + int pass = qualityPass + ( matDesc.coverage ? 1 : 0 ); + + if ( matDesc.coverage ) + { + Texture mainTex = matDesc.material.mainTexture; + if ( mainTex != null ) + matDesc.propertyBlock.SetTexture( "_MainTex", mainTex ); + if ( matDesc.cutoff ) + matDesc.propertyBlock.SetFloat( "_Cutoff", matDesc.material.GetFloat( "_Cutoff" ) ); + } + + renderCB.DrawMesh( m_clonedMesh, m_currLocalToWorld, m_owner.Instance.ClothVectorsMaterial, i, pass, matDesc.propertyBlock ); + } + + Profiler.EndSample(); + } + } +#endif +} +} diff --git a/Assets/Cinematic Effects/MotionBlur/Plugins/ClothState.cs.meta b/Assets/Cinematic Effects/MotionBlur/Plugins/ClothState.cs.meta new file mode 100644 index 0000000..2f84319 --- /dev/null +++ b/Assets/Cinematic Effects/MotionBlur/Plugins/ClothState.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: ee21680ad49e16d47baa6b281c4511d1 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/MotionBlur/Plugins/Editor.meta b/Assets/Cinematic Effects/MotionBlur/Plugins/Editor.meta new file mode 100644 index 0000000..b1069c5 --- /dev/null +++ b/Assets/Cinematic Effects/MotionBlur/Plugins/Editor.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 7dfaf547c29f54b01bfc82b484a511b6 +folderAsset: yes +timeCreated: 1461976949 +licenseType: Pro +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/MotionBlur/Plugins/Editor/About.cs b/Assets/Cinematic Effects/MotionBlur/Plugins/Editor/About.cs new file mode 100644 index 0000000..77703b9 --- /dev/null +++ b/Assets/Cinematic Effects/MotionBlur/Plugins/Editor/About.cs @@ -0,0 +1,92 @@ +// Amplify Motion - Full-scene Motion Blur for Unity Pro +// Copyright (c) Amplify Creations, Lda + +using System; +using System.Collections.Generic; +using UnityEngine; +using UnityEditor; + +namespace AmplifyMotion +{ + public class About : EditorWindow + { + private const string AboutImagePath = "AmplifyMotion/Textures/About.png"; + private Vector2 m_scrollPosition = Vector2.zero; + private Texture2D m_aboutImage; + + [MenuItem( "Window/Amplify Motion/About...", false, 20 )] + static void Init() + { + About window = ( About ) EditorWindow.GetWindow( typeof( About ) , true , "About Amplify Motion" ); + window.minSize = new Vector2( 502, 258 ); + window.maxSize = new Vector2( 502, 258 ); + window.Show(); + } + + public void OnFocus() + { + string[] guids = AssetDatabase.FindAssets( "About t:Texture" ); + string asset = ""; + + foreach ( string guid in guids ) + { + string path = AssetDatabase.GUIDToAssetPath( guid ); + if ( path.EndsWith( AboutImagePath ) ) + { + asset = path; + break; + } + } + + if ( !string.IsNullOrEmpty( asset ) ) + { + TextureImporter importer = AssetImporter.GetAtPath( asset ) as TextureImporter; + + if ( importer.textureType != TextureImporterType.GUI ) + { + importer.textureType = TextureImporterType.GUI; + AssetDatabase.ImportAsset( asset ); + } + + m_aboutImage = AssetDatabase.LoadAssetAtPath( asset, typeof( Texture2D ) ) as Texture2D; + } + else + Debug.LogWarning( "[AmplifyMotion] About image not found at " + AboutImagePath ); + } + + public void OnGUI() + { + m_scrollPosition = GUILayout.BeginScrollView( m_scrollPosition ); + + GUILayout.BeginVertical(); + + GUILayout.Space( 10 ); + + GUILayout.BeginHorizontal(); + GUILayout.FlexibleSpace(); + GUILayout.Box( m_aboutImage, GUIStyle.none ); + + if ( Event.current.type == EventType.MouseUp && GUILayoutUtility.GetLastRect().Contains( Event.current.mousePosition ) ) + Application.OpenURL( "http://www.amplify.pt" ); + + GUILayout.FlexibleSpace(); + GUILayout.EndHorizontal(); + + GUIStyle labelStyle = new GUIStyle( EditorStyles.label ); + labelStyle.alignment = TextAnchor.MiddleCenter; + labelStyle.wordWrap = true; + + GUILayout.Space( 10 ); + + GUILayout.Label( "\nAmplify Motion " + VersionInfo.StaticToString() + " - Full-scene Motion Blur", labelStyle, GUILayout.ExpandWidth( true ) ); + + GUILayout.Space( 6 ); + + GUILayout.Label( "\nCopyright (c) Amplify Creations, Lda. All rights reserved.\n", labelStyle, GUILayout.ExpandWidth( true ) ); + + GUILayout.EndVertical(); + + GUILayout.EndScrollView(); + } + } +} diff --git a/Assets/Cinematic Effects/MotionBlur/Plugins/Editor/About.cs.meta b/Assets/Cinematic Effects/MotionBlur/Plugins/Editor/About.cs.meta new file mode 100644 index 0000000..b103acc --- /dev/null +++ b/Assets/Cinematic Effects/MotionBlur/Plugins/Editor/About.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 8702049a56e8d69438a372d2291d93f6 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/MotionBlur/Plugins/Editor/AmplifyMotionEditor.dll b/Assets/Cinematic Effects/MotionBlur/Plugins/Editor/AmplifyMotionEditor.dll new file mode 100644 index 0000000000000000000000000000000000000000..a95f1aa599c37a4588cf38246a98e9ba5659743a GIT binary patch literal 3584 zcmeHJO=u)l5dL~H`P;Z_#C6%#MLRzWg3=5zvLX^E$wZAzen=;Ak&#W$%-cyz&%B|# zXH7gvE+YOMJc$Rvqu?or1sB1i;9&!M5KkU*^rV-C1rg&{uX{2X4gTy&F_pY}RrS8A zS5>e3^(?&lA$kC0ISvkho1BI6hW|O+;qsZszC42)gL@-4t>WIu>ZTvr%~01uuWnbo zMnlJTS=nK$Vfzicu;kixT~*HM)2GJM(93f`(dxm&AHBEU-fbV5ks)gc=%YmjX-XVy zjywl2Y~)Omw-_XULp$WO3-uuXwm{{-GpDMUNI#4Lt_XSHcIqeUA#DKnQP~{@E*={H zhF}8&M_>cgUpk^YvD%8M7bJ16nL2;BKg}CX7=;xso80mg1b;LzRhsior~*x(P0|) zgJbM1mQC3ABD-;~;y?0)l|8)GDz4af9`{Gi0wzL+hFe(*% zUDKsPsGDWIRZ6R{XG4{g-?k)2QgU@Gtf-PMzh0V-A{D!AteWfwrRUbHmQCgVUN)S* z=aQi#vMtgdseK=GR<6$Kun+_bp5I8GO{L6pDu{zijAL%s4*o>??{>g4hj|{@>8>HU z(R0Vx1t;H*D|sN67c!+dGf8Qk-`1<-bG&6;%wq|Q)aS`xpe*!N_NQOl_pLFc?D=%& zYu$B|in+jHF{+1P~hoBfs-gTk-FlPFULo@7SWA-=%fBUDVBX4gJ8u{mCB9qc->A<>;&a{PvL2C$6t#7i}? z!8VwCz + +using UnityEngine; +using UnityEditor; +using System.Collections; +using UnityEditor.Callbacks; +using UnityEditorInternal; + +[InitializeOnLoad] +[CustomEditor( typeof( AmplifyMotionObject ) )] +public class AmplifyMotionObjectEditor : AmplifyMotionObjectEditorBase +{ +} diff --git a/Assets/Cinematic Effects/MotionBlur/Plugins/Editor/AmplifyMotionObjectEditor.cs.meta b/Assets/Cinematic Effects/MotionBlur/Plugins/Editor/AmplifyMotionObjectEditor.cs.meta new file mode 100644 index 0000000..8b33994 --- /dev/null +++ b/Assets/Cinematic Effects/MotionBlur/Plugins/Editor/AmplifyMotionObjectEditor.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: fa9cf487ac20ad844953ae6d9746f058 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/MotionBlur/Plugins/Editor/AmplifyMotionObjectEditorBase.cs b/Assets/Cinematic Effects/MotionBlur/Plugins/Editor/AmplifyMotionObjectEditorBase.cs new file mode 100644 index 0000000..eb704c1 --- /dev/null +++ b/Assets/Cinematic Effects/MotionBlur/Plugins/Editor/AmplifyMotionObjectEditorBase.cs @@ -0,0 +1,13 @@ +// Amplify Motion - Full-scene Motion Blur for Unity Pro +// Copyright (c) Amplify Creations, Lda + +using UnityEngine; +using UnityEditor; +using System.Collections; +using System.Reflection; +using UnityEditor.Callbacks; +using UnityEditorInternal; + +public class AmplifyMotionObjectEditorBase : Editor +{ +} diff --git a/Assets/Cinematic Effects/MotionBlur/Plugins/Editor/AmplifyMotionObjectEditorBase.cs.meta b/Assets/Cinematic Effects/MotionBlur/Plugins/Editor/AmplifyMotionObjectEditorBase.cs.meta new file mode 100644 index 0000000..3746cc4 --- /dev/null +++ b/Assets/Cinematic Effects/MotionBlur/Plugins/Editor/AmplifyMotionObjectEditorBase.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 74f699bbe74c7f1469a9a32862bbaa9a +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/MotionBlur/Plugins/Editor/Resources.meta b/Assets/Cinematic Effects/MotionBlur/Plugins/Editor/Resources.meta new file mode 100644 index 0000000..84b80f5 --- /dev/null +++ b/Assets/Cinematic Effects/MotionBlur/Plugins/Editor/Resources.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: fe82cb816e6564133af86bf31fc695dd +folderAsset: yes +timeCreated: 1461976949 +licenseType: Pro +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/MotionBlur/Plugins/Editor/Resources/effect-icon.png b/Assets/Cinematic Effects/MotionBlur/Plugins/Editor/Resources/effect-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..d77d47ca184ffd90da7df151f3c99a7172c2c70c GIT binary patch literal 3586 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 IM6N<$g4_tiG5`Po literal 0 HcmV?d00001 diff --git a/Assets/Cinematic Effects/MotionBlur/Plugins/Editor/Resources/effect-icon.png.meta b/Assets/Cinematic Effects/MotionBlur/Plugins/Editor/Resources/effect-icon.png.meta new file mode 100644 index 0000000..a21974e --- /dev/null +++ b/Assets/Cinematic Effects/MotionBlur/Plugins/Editor/Resources/effect-icon.png.meta @@ -0,0 +1,55 @@ +fileFormatVersion: 2 +guid: 0ea3c819440ae8346ae765cd2a7d95cc +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: -2 + maxTextureSize: 32 + textureSettings: + filterMode: 0 + aniso: 1 + mipBias: -1 + wrapMode: 1 + nPOTScale: 0 + 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: 1 + textureType: 2 + buildTargetSettings: [] + spriteSheet: + sprites: [] + outline: [] + spritePackingTag: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/MotionBlur/Plugins/Editor/Resources/object-icon.tif b/Assets/Cinematic Effects/MotionBlur/Plugins/Editor/Resources/object-icon.tif new file mode 100644 index 0000000000000000000000000000000000000000..59717756783557608ccff6b06a42f0a4ce96fcf7 GIT binary patch literal 40236 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 literal 0 HcmV?d00001 diff --git a/Assets/Cinematic Effects/MotionBlur/Plugins/Editor/Resources/object-icon.tif.meta b/Assets/Cinematic Effects/MotionBlur/Plugins/Editor/Resources/object-icon.tif.meta new file mode 100644 index 0000000..89933bb --- /dev/null +++ b/Assets/Cinematic Effects/MotionBlur/Plugins/Editor/Resources/object-icon.tif.meta @@ -0,0 +1,55 @@ +fileFormatVersion: 2 +guid: be11958c9498dd048baecca8002f8212 +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: 128 + textureSettings: + filterMode: -1 + aniso: 1 + mipBias: -1 + wrapMode: 1 + nPOTScale: 0 + 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: 1 + textureType: 2 + buildTargetSettings: [] + spriteSheet: + sprites: [] + outline: [] + spritePackingTag: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/MotionBlur/Plugins/ParticleState.cs b/Assets/Cinematic Effects/MotionBlur/Plugins/ParticleState.cs new file mode 100644 index 0000000..d8b48d7 --- /dev/null +++ b/Assets/Cinematic Effects/MotionBlur/Plugins/ParticleState.cs @@ -0,0 +1,327 @@ +// Amplify Motion - Full-scene Motion Blur for Unity Pro +// Copyright (c) Amplify Creations, Lda + +#if UNITY_4_0 || UNITY_4_1 || UNITY_4_2 || UNITY_4_3 || UNITY_4_4 || UNITY_4_5 || UNITY_4_6 || UNITY_4_7 || UNITY_4_8 || UNITY_4_9 +#define UNITY_4 +#endif +#if UNITY_5_0 || UNITY_5_1 || UNITY_5_2 || UNITY_5_3 || UNITY_5_4 || UNITY_5_5 || UNITY_5_6 || UNITY_5_7 || UNITY_5_8 || UNITY_5_9 +#define UNITY_5 +#endif +#if UNITY_4 || UNITY_5_0 || UNITY_5_1 || UNITY_5_2 +#define UNITY_PRE_5_3 +#endif + +using System; +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.Profiling; + +#if !UNITY_PRE_5_3 +using UnityEngine.Rendering; + +namespace AmplifyMotion +{ +internal class ParticleState : AmplifyMotion.MotionState +{ + public class Particle + { + public int refCount; + public Matrix4x4 prevLocalToWorld; + public Matrix4x4 currLocalToWorld; + } + + public ParticleSystem m_particleSystem; + public ParticleSystemRenderer m_renderer; + + private Mesh m_mesh; + + private ParticleSystem.RotationOverLifetimeModule rotationOverLifetime; + private ParticleSystem.RotationBySpeedModule rotationBySpeed; + + private ParticleSystem.Particle[] m_particles; + private Dictionary m_particleDict; + private List m_listToRemove; + private Stack m_particleStack; + private int m_capacity; + + private MaterialDesc[] m_sharedMaterials; + + public bool m_moved = false; + private bool m_wasVisible; + + private static HashSet m_uniqueWarnings = new HashSet(); + + public ParticleState( AmplifyMotionCamera owner, AmplifyMotionObjectBase obj ) + : base( owner, obj ) + { + m_particleSystem = m_obj.GetComponent(); + m_renderer = m_particleSystem.GetComponent(); + rotationOverLifetime = m_particleSystem.rotationOverLifetime; + rotationBySpeed = m_particleSystem.rotationBySpeed; + } + + private Mesh CreateBillboardMesh() + { + int[] tris = new int[ 6 ] { 0, 1, 2, 2, 3, 0 }; + + Vector3[] vertices = new Vector3[ 4 ] { + new Vector3( -0.5f, -0.5f, 0 ), + new Vector3( 0.5f, -0.5f, 0 ), + new Vector3( 0.5f, 0.5f, 0 ), + new Vector3( -0.5f, 0.5f, 0 ) }; + + Vector2[] uv = new Vector2[ 4 ] { + new Vector2( 0, 0 ), + new Vector2( 1, 0 ), + new Vector2( 1, 1 ), + new Vector2( 0, 1 ) }; + + Mesh mesh = new Mesh(); + mesh.vertices = vertices; + mesh.uv = uv; + mesh.triangles = tris; + return mesh; + } + + private Mesh CreateStretchedBillboardMesh() + { + int[] tris = new int[ 6 ] { 0, 1, 2, 2, 3, 0 }; + + Vector3[] vertices = new Vector3[ 4 ] { + new Vector3( 0, -0.5f, -1.0f ), + new Vector3( 0, -0.5f, 0.0f ), + new Vector3( 0, 0.5f, 0.0f ), + new Vector3( 0, 0.5f, -1.0f ) + }; + + Vector2[] uv = new Vector2[ 4 ] { + new Vector2( 1, 1 ), + new Vector2( 0, 1 ), + new Vector2( 0, 0 ), + new Vector2( 1, 0 ) }; + + Mesh mesh = new Mesh(); + mesh.vertices = vertices; + mesh.uv = uv; + mesh.triangles = tris; + return mesh; + } + + internal override void Initialize() + { + if ( m_renderer == null ) + { + if ( !m_uniqueWarnings.Contains( m_obj ) ) + { + Debug.LogWarning( "[AmplifyMotion] Missing/Invalid Particle Renderer in object " + m_obj.name + ". Skipping." ); + m_uniqueWarnings.Add( m_obj ); + } + m_error = true; + return; + } + + base.Initialize(); + + if ( m_renderer.renderMode == ParticleSystemRenderMode.Mesh ) + m_mesh = m_renderer.mesh; + else if ( m_renderer.renderMode == ParticleSystemRenderMode.Stretch ) + m_mesh = CreateStretchedBillboardMesh(); + else + m_mesh = CreateBillboardMesh(); + + m_sharedMaterials = ProcessSharedMaterials( m_renderer.sharedMaterials ); + + m_capacity = m_particleSystem.maxParticles; + + m_particleDict = new Dictionary( m_capacity ); + m_particles = new ParticleSystem.Particle[ m_capacity ]; + m_listToRemove = new List( m_capacity ); + m_particleStack = new Stack( m_capacity ); + + for ( int k = 0; k < m_capacity; k++ ) + m_particleStack.Push( new Particle() ); + + m_wasVisible = false; + } + + void RemoveDeadParticles() + { + m_listToRemove.Clear(); + + var enumerator = m_particleDict.GetEnumerator(); + while ( enumerator.MoveNext() ) + { + KeyValuePair pair = enumerator.Current; + + if ( pair.Value.refCount <= 0 ) + { + m_particleStack.Push( pair.Value ); + if(!m_listToRemove.Contains(pair.Key)) + m_listToRemove.Add( pair.Key ); + } + else + pair.Value.refCount = 0; + } + + for ( int i = 0; i < m_listToRemove.Count; i++ ) + m_particleDict.Remove( m_listToRemove[ i ] ); + } + + internal override void UpdateTransform( CommandBuffer updateCB, bool starting ) + { + if ( !m_initialized || m_capacity != m_particleSystem.maxParticles ) + { + Initialize(); + return; + } + + Profiler.BeginSample( "Particle.Update" ); + + if ( !starting && m_wasVisible ) + { + var enumerator = m_particleDict.GetEnumerator(); + while ( enumerator.MoveNext() ) + { + Particle particle = enumerator.Current.Value; + particle.prevLocalToWorld = particle.currLocalToWorld; + } + } + + m_moved = true; + + int numAlive = m_particleSystem.GetParticles( m_particles ); + + Matrix4x4 transformLocalToWorld = Matrix4x4.TRS( m_transform.position, m_transform.rotation, Vector3.one ); + + bool separateAxes = ( rotationOverLifetime.enabled && rotationOverLifetime.separateAxes ) || + ( rotationBySpeed.enabled && rotationBySpeed.separateAxes ); + + for ( int i = 0; i < numAlive; i++ ) + { + uint seed = m_particles[ i ].randomSeed; + Particle particle; + + bool justSpawned = false; + if ( !m_particleDict.TryGetValue( seed, out particle ) && m_particleStack.Count > 0 ) + { + m_particleDict[ seed ] = particle = m_particleStack.Pop(); + justSpawned = true; + } + + if ( particle == null ) + continue; + + float currentSize = m_particles[ i ].GetCurrentSize( m_particleSystem ); + Vector3 size = new Vector3( currentSize, currentSize, currentSize ); + + Matrix4x4 particleCurrLocalToWorld; + if ( m_renderer.renderMode == ParticleSystemRenderMode.Mesh ) + { + Quaternion rotation; + if ( separateAxes ) + rotation = Quaternion.Euler( m_particles[ i ].rotation3D ); + else + rotation = Quaternion.AngleAxis( m_particles[ i ].rotation, m_particles[ i ].axisOfRotation ); + + Matrix4x4 particleMatrix = Matrix4x4.TRS( m_particles[ i ].position, rotation, size ); + + if ( m_particleSystem.simulationSpace == ParticleSystemSimulationSpace.World ) + particleCurrLocalToWorld = particleMatrix; + else + particleCurrLocalToWorld = transformLocalToWorld * particleMatrix; + } + else if ( m_renderer.renderMode == ParticleSystemRenderMode.Billboard ) + { + if ( m_particleSystem.simulationSpace == ParticleSystemSimulationSpace.Local ) + m_particles[ i ].position = transformLocalToWorld.MultiplyPoint( m_particles[ i ].position ); + + Quaternion rotation; + if ( separateAxes ) + rotation = Quaternion.Euler( -m_particles[ i ].rotation3D.x, -m_particles[ i ].rotation3D.y, m_particles[ i ].rotation3D.z ); + else + rotation = Quaternion.AngleAxis( m_particles[ i ].rotation, Vector3.back ); + + particleCurrLocalToWorld = Matrix4x4.TRS( m_particles[ i ].position, m_owner.Transform.rotation * rotation, size ); + } + else + { + // unsupported + particleCurrLocalToWorld = Matrix4x4.identity; + } + + particle.refCount = 1; + particle.currLocalToWorld = particleCurrLocalToWorld; + if ( justSpawned ) + particle.prevLocalToWorld = particle.currLocalToWorld; + } + + if ( starting || !m_wasVisible ) + { + var enumerator = m_particleDict.GetEnumerator(); + while ( enumerator.MoveNext() ) + { + Particle particle = enumerator.Current.Value; + particle.prevLocalToWorld = particle.currLocalToWorld; + } + } + + RemoveDeadParticles(); + + m_wasVisible = m_renderer.isVisible; + + Profiler.EndSample(); + } + + internal override void RenderVectors( Camera camera, CommandBuffer renderCB, float scale, AmplifyMotion.Quality quality ) + { + Profiler.BeginSample( "Particle.Render" ); + + // TODO: batch + + if ( m_initialized && !m_error && m_renderer.isVisible ) + { + bool mask = ( m_owner.Instance.CullingMask & ( 1 << m_obj.gameObject.layer ) ) != 0; + if ( !mask || ( mask && m_moved ) ) + { + const float rcp255 = 1 / 255.0f; + int objectId = mask ? m_owner.Instance.GenerateObjectId( m_obj.gameObject ) : 255; + + renderCB.SetGlobalFloat( "_AM_OBJECT_ID", objectId * rcp255 ); + renderCB.SetGlobalFloat( "_AM_MOTION_SCALE", mask ? scale : 0 ); + + int qualityPass = ( quality == AmplifyMotion.Quality.Mobile ) ? 0 : 2; + + for ( int i = 0; i < m_sharedMaterials.Length; i++ ) + { + MaterialDesc matDesc = m_sharedMaterials[ i ]; + int pass = qualityPass + ( matDesc.coverage ? 1 : 0 ); + + if ( matDesc.coverage ) + { + Texture mainTex = matDesc.material.mainTexture; + if ( mainTex != null ) + matDesc.propertyBlock.SetTexture( "_MainTex", mainTex ); + if ( matDesc.cutoff ) + matDesc.propertyBlock.SetFloat( "_Cutoff", matDesc.material.GetFloat( "_Cutoff" ) ); + } + + var enumerator = m_particleDict.GetEnumerator(); + while ( enumerator.MoveNext() ) + { + KeyValuePair pair = enumerator.Current; + + Matrix4x4 prevModelViewProj = m_owner.PrevViewProjMatrixRT * pair.Value.prevLocalToWorld; + renderCB.SetGlobalMatrix( "_AM_MATRIX_PREV_MVP", prevModelViewProj ); + + renderCB.DrawMesh( m_mesh, pair.Value.currLocalToWorld, m_owner.Instance.SolidVectorsMaterial, i, pass, matDesc.propertyBlock ); + } + } + } + } + + Profiler.EndSample(); + } +} +} + +#endif diff --git a/Assets/Cinematic Effects/MotionBlur/Plugins/ParticleState.cs.meta b/Assets/Cinematic Effects/MotionBlur/Plugins/ParticleState.cs.meta new file mode 100644 index 0000000..4b9eb3a --- /dev/null +++ b/Assets/Cinematic Effects/MotionBlur/Plugins/ParticleState.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 9f0d513b4e0749b4d9367ab62c348623 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/MotionBlur/Plugins/Runtime.meta b/Assets/Cinematic Effects/MotionBlur/Plugins/Runtime.meta new file mode 100644 index 0000000..cbe33a9 --- /dev/null +++ b/Assets/Cinematic Effects/MotionBlur/Plugins/Runtime.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: c11944833b1df48bdbdad6a591d010cf +folderAsset: yes +timeCreated: 1461976949 +licenseType: Pro +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/MotionBlur/Plugins/Runtime/VersionInfo.cs b/Assets/Cinematic Effects/MotionBlur/Plugins/Runtime/VersionInfo.cs new file mode 100644 index 0000000..4b456f3 --- /dev/null +++ b/Assets/Cinematic Effects/MotionBlur/Plugins/Runtime/VersionInfo.cs @@ -0,0 +1,64 @@ +// Amplify Motion - Full-scene Motion Blur for Unity Pro +// Copyright (c) Amplify Creations, Lda + +using System; +using UnityEngine; + +namespace AmplifyMotion +{ + [Serializable] + public class VersionInfo + { + public const byte Major = 1; + public const byte Minor = 7; + public const byte Release = 1; + + private static string StageSuffix = "_dev001"; + + #if TRIAL + private static string TrialSuffix = " Trial"; + #else + private static string TrialSuffix = ""; + #endif + + public static string StaticToString() + { + return string.Format( "{0}.{1}.{2}", Major, Minor, Release ) + StageSuffix + TrialSuffix; + } + + public override string ToString() + { + return string.Format( "{0}.{1}.{2}", m_major, m_minor, m_release ) + StageSuffix + TrialSuffix; + } + + public int Number { get { return m_major * 100 + m_minor * 10 + m_release; } } + + [SerializeField] private int m_major; + [SerializeField] private int m_minor; + [SerializeField] private int m_release; + + VersionInfo() + { + m_major = Major; + m_minor = Minor; + m_release = Release; + } + + VersionInfo( byte major, byte minor, byte release ) + { + m_major = major; + m_minor = minor; + m_release = release; + } + + public static VersionInfo Current() + { + return new VersionInfo( Major, Minor, Release ); + } + + public static bool Matches( VersionInfo version ) + { + return ( Major == version.m_major ) && ( Minor == version.m_minor ) && ( Release == version.m_release ); + } + } +} diff --git a/Assets/Cinematic Effects/MotionBlur/Plugins/Runtime/VersionInfo.cs.meta b/Assets/Cinematic Effects/MotionBlur/Plugins/Runtime/VersionInfo.cs.meta new file mode 100644 index 0000000..19e5f71 --- /dev/null +++ b/Assets/Cinematic Effects/MotionBlur/Plugins/Runtime/VersionInfo.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 69a9dd9acbcff9d45acbf435fddd6110 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/MotionBlur/Plugins/SkinnedState.cs b/Assets/Cinematic Effects/MotionBlur/Plugins/SkinnedState.cs new file mode 100644 index 0000000..bf231cd --- /dev/null +++ b/Assets/Cinematic Effects/MotionBlur/Plugins/SkinnedState.cs @@ -0,0 +1,848 @@ +// Amplify Motion - Full-scene Motion Blur for Unity Pro +// Copyright (c) Amplify Creations, Lda + +#if UNITY_4_0 || UNITY_4_1 || UNITY_4_2 || UNITY_4_3 || UNITY_4_4 || UNITY_4_5 || UNITY_4_6 || UNITY_4_7 || UNITY_4_8 || UNITY_4_9 +#define UNITY_4 +#endif +#if UNITY_5_0 || UNITY_5_1 || UNITY_5_2 || UNITY_5_3 || UNITY_5_4 || UNITY_5_5 || UNITY_5_6 || UNITY_5_7 || UNITY_5_8 || UNITY_5_9 +#define UNITY_5 +#endif + +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using System.Threading; +using UnityEngine; +using UnityEngine.Profiling; +#if !UNITY_4 +using UnityEngine.Rendering; +#endif + +namespace AmplifyMotion +{ +internal class SkinnedState : AmplifyMotion.MotionState +{ + private SkinnedMeshRenderer m_renderer; + + private int m_boneCount; + private Transform[] m_boneTransforms; + private Matrix4x4[] m_bones; + + private int m_weightCount; + private int[] m_boneIndices; + private float[] m_boneWeights; + + private int m_vertexCount; + private Vector4[] m_baseVertices; + private Vector3[] m_prevVertices; + private Vector3[] m_currVertices; + +#if !UNITY_4 + private int m_gpuBoneTexWidth; + private int m_gpuBoneTexHeight; + private int m_gpuVertexTexWidth; + private int m_gpuVertexTexHeight; + private Material m_gpuSkinDeformMat; + private Color[] m_gpuBoneData; + private Texture2D m_gpuBones; + private Texture2D m_gpuBoneIndices; + private Texture2D[] m_gpuBaseVertices; + private RenderTexture m_gpuPrevVertices; + private RenderTexture m_gpuCurrVertices; +#endif + + private Mesh m_clonedMesh; + private Matrix4x4 m_worldToLocalMatrix; + private Matrix4x4 m_prevLocalToWorld; + private Matrix4x4 m_currLocalToWorld; + + private MaterialDesc[] m_sharedMaterials; + + private ManualResetEvent m_asyncUpdateSignal = null; + private bool m_asyncUpdateTriggered = false; + + private bool m_starting; + private bool m_wasVisible; + private bool m_useFallback; + private bool m_useGPU = false; + + private static HashSet m_uniqueWarnings = new HashSet(); + + public SkinnedState( AmplifyMotionCamera owner, AmplifyMotionObjectBase obj ) + : base( owner, obj ) + { + m_renderer = m_obj.GetComponent(); + } + + internal override void Initialize() + { + if ( !m_renderer.sharedMesh.isReadable ) + { + if ( !m_uniqueWarnings.Contains( m_obj ) ) + { + Debug.LogWarning( "[AmplifyMotion] Read/Write Import Setting disabled in object " + m_obj.name + ". Skipping." ); + m_uniqueWarnings.Add( m_obj ); + } + m_error = true; + return; + } + + // find out if we're forced to use the fallback path + Transform[] bones = m_renderer.bones; + m_useFallback = ( bones == null || bones.Length == 0 ); + + if ( !m_useFallback ) + m_useGPU = m_owner.Instance.CanUseGPU; // use GPU, if allowed + + base.Initialize(); + + m_vertexCount = m_renderer.sharedMesh.vertexCount; + m_prevVertices = new Vector3[ m_vertexCount ]; + m_currVertices = new Vector3[ m_vertexCount ]; + m_clonedMesh = new Mesh(); + + if ( !m_useFallback ) + { + if ( m_renderer.quality == SkinQuality.Auto ) + m_weightCount = ( int ) QualitySettings.blendWeights; + else + m_weightCount = ( int ) m_renderer.quality; + + m_boneTransforms = m_renderer.bones; + m_boneCount = m_renderer.bones.Length; + m_bones = new Matrix4x4[ m_boneCount ]; + + Vector4[] baseVertices = new Vector4[ m_vertexCount * m_weightCount ]; + int[] boneIndices = new int[ m_vertexCount * m_weightCount ]; + float[] boneWeights = ( m_weightCount > 1 ) ? new float[ m_vertexCount * m_weightCount ] : null; + + if ( m_weightCount == 1 ) + InitializeBone1( baseVertices, boneIndices ); + else if ( m_weightCount == 2 ) + InitializeBone2( baseVertices, boneIndices, boneWeights ); + else + InitializeBone4( baseVertices, boneIndices, boneWeights ); + + m_baseVertices = baseVertices; + m_boneIndices = boneIndices; + m_boneWeights = boneWeights; + + Mesh skinnedMesh = m_renderer.sharedMesh; + + m_clonedMesh.vertices = skinnedMesh.vertices; + m_clonedMesh.normals = skinnedMesh.vertices; + m_clonedMesh.uv = skinnedMesh.uv; + m_clonedMesh.subMeshCount = skinnedMesh.subMeshCount; + for ( int i = 0; i < skinnedMesh.subMeshCount; i++ ) + m_clonedMesh.SetTriangles( skinnedMesh.GetTriangles( i ), i ); + + #if !UNITY_4 + if ( m_useGPU ) + { + if ( !InitializeGPUSkinDeform() ) + { + // fallback + Debug.LogWarning( "[AmplifyMotion] Failed initializing GPU skin deform for object " + m_obj.name + ". Falling back to CPU path." ); + m_useGPU = false; + } + else + { + // release unnecessary data + m_boneIndices = null; + m_boneWeights = null; + + m_baseVertices = null; + m_prevVertices = null; + m_currVertices = null; + } + } + #endif + + if ( !m_useGPU ) + { + m_asyncUpdateSignal = new ManualResetEvent( false ); + m_asyncUpdateTriggered = false; + } + } + + m_sharedMaterials = ProcessSharedMaterials( m_renderer.sharedMaterials ); + + m_wasVisible = false; + } + + internal override void Shutdown() + { + if ( !m_useFallback && !m_useGPU ) + WaitForAsyncUpdate(); + + #if !UNITY_4 + if ( m_useGPU ) + ShutdownGPUSkinDeform(); + #endif + + if ( m_clonedMesh != null ) + { + Mesh.Destroy( m_clonedMesh ); + m_clonedMesh = null; + } + + m_boneTransforms = null; + m_bones = null; + m_boneIndices = null; + m_boneWeights = null; + m_baseVertices = null; + m_prevVertices = null; + m_currVertices = null; + m_sharedMaterials = null; + } + +#if !UNITY_4 + private bool InitializeGPUSkinDeform() + { + bool succeeded = true; + try + { + m_gpuBoneTexWidth = Mathf.NextPowerOfTwo( m_boneCount ); + m_gpuBoneTexHeight = 4; + m_gpuVertexTexWidth = Mathf.NextPowerOfTwo( Mathf.CeilToInt( Mathf.Sqrt( m_vertexCount ) ) ); + m_gpuVertexTexHeight = Mathf.NextPowerOfTwo( Mathf.CeilToInt( m_vertexCount / ( float ) m_gpuVertexTexWidth ) ); + + // gpu skin deform material + m_gpuSkinDeformMat = new Material( Shader.Find( "Hidden/Amplify Motion/GPUSkinDeform" ) ) { hideFlags = HideFlags.DontSave }; + + // bone matrix texture + m_gpuBones = new Texture2D( m_gpuBoneTexWidth, m_gpuBoneTexHeight, TextureFormat.RGBAFloat, false, true ); + m_gpuBones.hideFlags = HideFlags.DontSave; + m_gpuBones.name = "AM-" + m_obj.name + "-Bones"; + m_gpuBones.filterMode = FilterMode.Point; + + m_gpuBoneData = new Color[ m_gpuBoneTexWidth * m_gpuBoneTexHeight ]; + + UpdateBonesGPU(); + + // vertex bone index/weight textures + TextureFormat boneIDWFormat = TextureFormat.RHalf; + boneIDWFormat = ( m_weightCount == 2 ) ? TextureFormat.RGHalf : boneIDWFormat; + boneIDWFormat = ( m_weightCount == 4 ) ? TextureFormat.RGBAHalf : boneIDWFormat; + + m_gpuBoneIndices = new Texture2D( m_gpuVertexTexWidth, m_gpuVertexTexHeight, boneIDWFormat, false, true ); + m_gpuBoneIndices.hideFlags = HideFlags.DontSave; + m_gpuBoneIndices.name = "AM-" + m_obj.name + "-Bones"; + m_gpuBoneIndices.filterMode = FilterMode.Point; + m_gpuBoneIndices.wrapMode = TextureWrapMode.Clamp; + + BoneWeight[] meshBoneWeights = m_renderer.sharedMesh.boneWeights; + Color[] boneIndices = new Color[ m_gpuVertexTexWidth * m_gpuVertexTexHeight ]; + + for ( int v = 0; v < m_vertexCount; v++ ) + { + int x = v % m_gpuVertexTexWidth; + int y = v / m_gpuVertexTexWidth; + int offset = y * m_gpuVertexTexWidth + x; + + BoneWeight boneWeight = meshBoneWeights[ v ]; + boneIndices[ offset ] = new Vector4( boneWeight.boneIndex0, boneWeight.boneIndex1, boneWeight.boneIndex2, boneWeight.boneIndex3 ); + } + m_gpuBoneIndices.SetPixels( boneIndices ); + m_gpuBoneIndices.Apply(); + + // base vertex textures + m_gpuBaseVertices = new Texture2D[ m_weightCount ]; + for ( int w = 0; w < m_weightCount; w++ ) + { + m_gpuBaseVertices[ w ] = new Texture2D( m_gpuVertexTexWidth, m_gpuVertexTexHeight, TextureFormat.RGBAFloat, false, true ); + m_gpuBaseVertices[ w ].hideFlags = HideFlags.DontSave; + m_gpuBaseVertices[ w ].name = "AM-" + m_obj.name + "-BaseVerts"; + m_gpuBaseVertices[ w ].filterMode = FilterMode.Point; + } + + List baseVertices = new List( m_weightCount ); + for ( int w = 0; w < m_weightCount; w++ ) + baseVertices.Add( new Color[ m_gpuVertexTexWidth * m_gpuVertexTexHeight ] ); + + for ( int v = 0; v < m_vertexCount; v++ ) + { + int x = v % m_gpuVertexTexWidth; + int y = v / m_gpuVertexTexWidth; + int offset = y * m_gpuVertexTexWidth + x; + + for ( int w = 0; w < m_weightCount; w++ ) + baseVertices[ w ][ offset ] = m_baseVertices[ v * m_weightCount + w ]; + } + for ( int w = 0; w < m_weightCount; w++ ) + { + m_gpuBaseVertices[ w ].SetPixels( baseVertices[ w ] ); + m_gpuBaseVertices[ w ].Apply(); + } + + // create output/target vertex render textures + m_gpuPrevVertices = new RenderTexture( m_gpuVertexTexWidth, m_gpuVertexTexHeight, 0, RenderTextureFormat.ARGBFloat, RenderTextureReadWrite.Linear ); + m_gpuPrevVertices.hideFlags = HideFlags.DontSave; + m_gpuPrevVertices.name = "AM-" + m_obj.name + "-PrevVerts"; + m_gpuPrevVertices.filterMode = FilterMode.Point; + m_gpuPrevVertices.wrapMode = TextureWrapMode.Clamp; + m_gpuPrevVertices.Create(); + + m_gpuCurrVertices = new RenderTexture( m_gpuVertexTexWidth, m_gpuVertexTexHeight, 0, RenderTextureFormat.ARGBFloat, RenderTextureReadWrite.Linear ); + m_gpuCurrVertices.hideFlags = HideFlags.DontSave; + m_gpuCurrVertices.name = "AM-" + m_obj.name + "-CurrVerts"; + m_gpuCurrVertices.filterMode = FilterMode.Point; + m_gpuCurrVertices.wrapMode = TextureWrapMode.Clamp; + m_gpuCurrVertices.Create(); + + // assign local material constants + m_gpuSkinDeformMat.SetTexture( "_AM_BONE_TEX", m_gpuBones ); + m_gpuSkinDeformMat.SetTexture( "_AM_BONE_INDEX_TEX", m_gpuBoneIndices ); + for ( int w = 0; w < m_weightCount; w++ ) + m_gpuSkinDeformMat.SetTexture( "_AM_BASE_VERTEX" + w + "_TEX", m_gpuBaseVertices[ w ] ); + + // assign global shader constants + Vector4 boneTexelSize = new Vector4( 1.0f / m_gpuBoneTexWidth, 1.0f / m_gpuBoneTexHeight, m_gpuBoneTexWidth, m_gpuBoneTexHeight ); + Vector4 vertexTexelSize = new Vector4( 1.0f / m_gpuVertexTexWidth, 1.0f / m_gpuVertexTexHeight, m_gpuVertexTexWidth, m_gpuVertexTexHeight ); + + m_gpuSkinDeformMat.SetVector( "_AM_BONE_TEXEL_SIZE", boneTexelSize ); + m_gpuSkinDeformMat.SetVector( "_AM_BONE_TEXEL_HALFSIZE", boneTexelSize * 0.5f ); + m_gpuSkinDeformMat.SetVector( "_AM_VERTEX_TEXEL_SIZE", vertexTexelSize ); + m_gpuSkinDeformMat.SetVector( "_AM_VERTEX_TEXEL_HALFSIZE", vertexTexelSize * 0.5f ); + + // assign vertex x/y offsets packed into second uv channel + Vector2[] indexCoords = new Vector2[ m_vertexCount ]; + for ( int v = 0; v < m_vertexCount; v++ ) + { + int x = v % m_gpuVertexTexWidth; + int y = v / m_gpuVertexTexWidth; + float x_norm = ( x / ( float ) m_gpuVertexTexWidth ) + vertexTexelSize.x * 0.5f; + float y_norm = ( y / ( float ) m_gpuVertexTexHeight ) + vertexTexelSize.y * 0.5f; + indexCoords[ v ] = new Vector2( x_norm, y_norm ); + } + m_clonedMesh.uv2 = indexCoords; + } + catch ( Exception ) + { + succeeded = false; + } + return succeeded; + } + + private void ShutdownGPUSkinDeform() + { + if ( m_gpuSkinDeformMat != null ) + { + Material.DestroyImmediate( m_gpuSkinDeformMat ); + m_gpuSkinDeformMat = null; + } + + m_gpuBoneData = null; + + if ( m_gpuBones != null ) + { + Texture2D.DestroyImmediate( m_gpuBones ); + m_gpuBones = null; + } + + if ( m_gpuBoneIndices != null ) + { + Texture2D.DestroyImmediate( m_gpuBoneIndices ); + m_gpuBoneIndices = null; + } + + if ( m_gpuBaseVertices != null ) + { + for ( int i = 0; i < m_gpuBaseVertices.Length; i++ ) + Texture2D.DestroyImmediate( m_gpuBaseVertices[ i ] ); + m_gpuBaseVertices = null; + } + + if ( m_gpuPrevVertices != null ) + { + RenderTexture.active = null; + m_gpuPrevVertices.Release(); + RenderTexture.DestroyImmediate( m_gpuPrevVertices ); + m_gpuPrevVertices = null; + } + + if ( m_gpuCurrVertices != null ) + { + RenderTexture.active = null; + m_gpuCurrVertices.Release(); + RenderTexture.DestroyImmediate( m_gpuCurrVertices ); + m_gpuCurrVertices = null; + } + } + + private void UpdateBonesGPU() + { + for ( int b = 0; b < m_boneCount; b++ ) + { + for ( int r = 0; r < m_gpuBoneTexHeight; r++ ) + m_gpuBoneData[ r * m_gpuBoneTexWidth + b ] = m_bones[ b ].GetRow( r ); + } + m_gpuBones.SetPixels( m_gpuBoneData ); + m_gpuBones.Apply(); + } + + private void UpdateVerticesGPU( CommandBuffer updateCB, bool starting ) + { + if ( !starting && m_wasVisible ) + { + AmplifyMotionEffectBase.DiscardContents( m_gpuPrevVertices ); + updateCB.Blit( new RenderTargetIdentifier( m_gpuCurrVertices ), m_gpuPrevVertices ); + } + + updateCB.SetGlobalMatrix( "_AM_WORLD_TO_LOCAL_MATRIX", m_worldToLocalMatrix ); + + AmplifyMotionEffectBase.DiscardContents( m_gpuCurrVertices ); + RenderTexture dummy = null; + updateCB.Blit( new RenderTargetIdentifier( dummy ), m_gpuCurrVertices, m_gpuSkinDeformMat, Mathf.Min( m_weightCount - 1, 2 ) ); + + if ( starting || !m_wasVisible ) + { + AmplifyMotionEffectBase.DiscardContents( m_gpuPrevVertices ); + updateCB.Blit( new RenderTargetIdentifier( m_gpuCurrVertices ), m_gpuPrevVertices ); + } + } +#endif + + private void UpdateBones() + { + for ( int b = 0; b < m_boneCount; b++ ) + m_bones[ b ] = ( m_boneTransforms[ b ] != null ) ? m_boneTransforms[ b ].localToWorldMatrix : Matrix4x4.identity; + + m_worldToLocalMatrix = m_transform.worldToLocalMatrix; + + #if !UNITY_4 + if ( m_useGPU ) + { + Profiler.BeginSample( "UpdateBonesGPU" ); + UpdateBonesGPU(); + Profiler.EndSample(); + } + #endif + } + + private void UpdateVerticesFallback( bool starting ) + { + if ( !starting && m_wasVisible ) + Array.Copy( m_currVertices, m_prevVertices, m_vertexCount ); + + m_renderer.BakeMesh( m_clonedMesh ); + + Array.Copy( m_clonedMesh.vertices, m_currVertices, m_vertexCount ); + + if ( starting || !m_wasVisible ) + Array.Copy( m_currVertices, m_prevVertices, m_vertexCount ); + } + + private void AsyncUpdateVertices( bool starting ) + { + if ( !starting && m_wasVisible ) + Array.Copy( m_currVertices, m_prevVertices, m_vertexCount ); + + for ( int i = 0; i < m_boneCount; i++ ) + m_bones[ i ] = m_worldToLocalMatrix * m_bones[ i ]; + + if ( m_weightCount == 1 ) + UpdateVerticesBone1(); + else if ( m_weightCount == 2 ) + UpdateVerticesBone2(); + else + UpdateVerticesBone4(); + + if ( starting || !m_wasVisible ) + Array.Copy( m_currVertices, m_prevVertices, m_vertexCount ); + } + + private void InitializeBone1( Vector4[] baseVertices, int[] boneIndices ) + { + Vector3[] meshVertices = m_renderer.sharedMesh.vertices; + Matrix4x4[] meshBindPoses = m_renderer.sharedMesh.bindposes; + BoneWeight[] meshBoneWeights = m_renderer.sharedMesh.boneWeights; + + for ( int i = 0; i < m_vertexCount; i++ ) + { + int offset0 = i * m_weightCount; + + int bone0 = boneIndices[ offset0 ] = meshBoneWeights[ i ].boneIndex0; + Vector3 baseVertex0 = meshBindPoses[ bone0 ].MultiplyPoint3x4( meshVertices[ i ] ); + + baseVertices[ offset0 ] = new Vector4( baseVertex0.x, baseVertex0.y, baseVertex0.z, 1.0f ); + } + } + + private void InitializeBone2( Vector4[] baseVertices, int[] boneIndices, float[] boneWeights ) + { + Vector3[] meshVertices = m_renderer.sharedMesh.vertices; + Matrix4x4[] meshBindPoses = m_renderer.sharedMesh.bindposes; + BoneWeight[] meshBoneWeights = m_renderer.sharedMesh.boneWeights; + + for ( int i = 0; i < m_vertexCount; i++ ) + { + int offset0 = i * m_weightCount; + int offset1 = offset0 + 1; + + BoneWeight boneWeight = meshBoneWeights[ i ]; + int bone0 = boneIndices[ offset0 ] = boneWeight.boneIndex0; + int bone1 = boneIndices[ offset1 ] = boneWeight.boneIndex1; + + float weight0 = boneWeight.weight0; + float weight1 = boneWeight.weight1; + + float rcpSum = 1.0f / ( weight0 + weight1 ); + boneWeights[ offset0 ] = weight0 = weight0 * rcpSum; + boneWeights[ offset1 ] = weight1 = weight1 * rcpSum; + + Vector3 baseVertex0 = weight0 * meshBindPoses[ bone0 ].MultiplyPoint3x4( meshVertices[ i ] ); + Vector3 baseVertex1 = weight1 * meshBindPoses[ bone1 ].MultiplyPoint3x4( meshVertices[ i ] ); + + baseVertices[ offset0 ] = new Vector4( baseVertex0.x, baseVertex0.y, baseVertex0.z, weight0 ); + baseVertices[ offset1 ] = new Vector4( baseVertex1.x, baseVertex1.y, baseVertex1.z, weight1 ); + } + } + + private void InitializeBone4( Vector4[] baseVertices, int[] boneIndices, float[] boneWeights ) + { + Vector3[] meshVertices = m_renderer.sharedMesh.vertices; + Matrix4x4[] meshBindPoses = m_renderer.sharedMesh.bindposes; + BoneWeight[] meshBoneWeights = m_renderer.sharedMesh.boneWeights; + + for ( int i = 0; i < m_vertexCount; i++ ) + { + int offset0 = i * m_weightCount; + int offset1 = offset0 + 1; + int offset2 = offset0 + 2; + int offset3 = offset0 + 3; + + BoneWeight boneWeight = meshBoneWeights[ i ]; + int bone0 = boneIndices[ offset0 ] = boneWeight.boneIndex0; + int bone1 = boneIndices[ offset1 ] = boneWeight.boneIndex1; + int bone2 = boneIndices[ offset2 ] = boneWeight.boneIndex2; + int bone3 = boneIndices[ offset3 ] = boneWeight.boneIndex3; + + float weight0 = boneWeights[ offset0 ] = boneWeight.weight0; + float weight1 = boneWeights[ offset1 ] = boneWeight.weight1; + float weight2 = boneWeights[ offset2 ] = boneWeight.weight2; + float weight3 = boneWeights[ offset3 ] = boneWeight.weight3; + + Vector3 baseVertex0 = weight0 * meshBindPoses[ bone0 ].MultiplyPoint3x4( meshVertices[ i ] ); + Vector3 baseVertex1 = weight1 * meshBindPoses[ bone1 ].MultiplyPoint3x4( meshVertices[ i ] ); + Vector3 baseVertex2 = weight2 * meshBindPoses[ bone2 ].MultiplyPoint3x4( meshVertices[ i ] ); + Vector3 baseVertex3 = weight3 * meshBindPoses[ bone3 ].MultiplyPoint3x4( meshVertices[ i ] ); + + baseVertices[ offset0 ] = new Vector4( baseVertex0.x, baseVertex0.y, baseVertex0.z, weight0 ); + baseVertices[ offset1 ] = new Vector4( baseVertex1.x, baseVertex1.y, baseVertex1.z, weight1 ); + baseVertices[ offset2 ] = new Vector4( baseVertex2.x, baseVertex2.y, baseVertex2.z, weight2 ); + baseVertices[ offset3 ] = new Vector4( baseVertex3.x, baseVertex3.y, baseVertex3.z, weight3 ); + } + } + + private void UpdateVerticesBone1() + { + for ( int i = 0; i < m_vertexCount; i++ ) + MulPoint3x4_XYZ( ref m_currVertices[ i ], ref m_bones[ m_boneIndices[ i ] ], m_baseVertices[ i ] ); + } + + private void UpdateVerticesBone2() + { + Vector3 deformedVertex = Vector3.zero; + for ( int i = 0; i < m_vertexCount; i++ ) + { + int offset0 = i * 2; + int offset1 = offset0 + 1; + + int b0 = m_boneIndices[ offset0 ]; + int b1 = m_boneIndices[ offset1 ]; + float weight1 = m_boneWeights[ offset1 ]; + + MulPoint3x4_XYZW( ref deformedVertex, ref m_bones[ b0 ], m_baseVertices[ offset0 ] ); + if ( weight1 != 0 ) + MulAddPoint3x4_XYZW( ref deformedVertex, ref m_bones[ b1 ], m_baseVertices[ offset1 ] ); + + m_currVertices[ i ] = deformedVertex; + } + } + + private void UpdateVerticesBone4() + { + Vector3 deformedVertex = Vector3.zero; + for ( int i = 0; i < m_vertexCount; i++ ) + { + int offset0 = i * 4; + int offset1 = offset0 + 1; + int offset2 = offset0 + 2; + int offset3 = offset0 + 3; + + int b0 = m_boneIndices[ offset0 ]; + int b1 = m_boneIndices[ offset1 ]; + int b2 = m_boneIndices[ offset2 ]; + int b3 = m_boneIndices[ offset3 ]; + + float weight1 = m_boneWeights[ offset1 ]; + float weight2 = m_boneWeights[ offset2 ]; + float weight3 = m_boneWeights[ offset3 ]; + + MulPoint3x4_XYZW( ref deformedVertex, ref m_bones[ b0 ], m_baseVertices[ offset0 ] ); + if ( weight1 != 0 ) + MulAddPoint3x4_XYZW( ref deformedVertex, ref m_bones[ b1 ], m_baseVertices[ offset1 ] ); + if ( weight2 != 0 ) + MulAddPoint3x4_XYZW( ref deformedVertex, ref m_bones[ b2 ], m_baseVertices[ offset2 ] ); + if ( weight3 != 0 ) + MulAddPoint3x4_XYZW( ref deformedVertex, ref m_bones[ b3 ], m_baseVertices[ offset3 ] ); + + m_currVertices[ i ] = deformedVertex; + } + } + + internal override void AsyncUpdate() + { + try + { + AsyncUpdateVertices( m_starting ); + } + catch ( System.Exception e ) + { + Debug.LogError( "[AmplifyMotion] Failed on SkinnedMeshRenderer data. Please contact support.\n" + e.Message ); + } + finally + { + m_asyncUpdateSignal.Set(); + } + } + +#if UNITY_4 + internal override void UpdateTransform( bool starting ) +#else + internal override void UpdateTransform( CommandBuffer updateCB, bool starting ) +#endif + { + if ( !m_initialized ) + { + Initialize(); + return; + } + + Profiler.BeginSample( "Skinned.Update" ); + + if ( !starting && m_wasVisible ) + m_prevLocalToWorld = m_currLocalToWorld; + + bool isVisible = m_renderer.isVisible; + + if ( !m_error && ( isVisible || starting ) ) + { + UpdateBones(); + + m_starting = !m_wasVisible || starting; + + if ( !m_useFallback ) + { + if ( !m_useGPU ) + { + m_asyncUpdateSignal.Reset(); + m_asyncUpdateTriggered = true; + m_owner.Instance.WorkerPool.EnqueueAsyncUpdate( this ); + } + #if !UNITY_4 + else + UpdateVerticesGPU( updateCB, m_starting ); + #endif + } + else + UpdateVerticesFallback( m_starting ); + } + + if ( !m_useFallback ) + m_currLocalToWorld = m_transform.localToWorldMatrix; + else + m_currLocalToWorld = Matrix4x4.TRS( m_transform.position, m_transform.rotation, Vector3.one ); + + if ( starting || !m_wasVisible ) + m_prevLocalToWorld = m_currLocalToWorld; + + m_wasVisible = isVisible; + + Profiler.EndSample(); + } + + private void WaitForAsyncUpdate() + { + if ( m_asyncUpdateTriggered ) + { + if ( !m_asyncUpdateSignal.WaitOne( MotionState.AsyncUpdateTimeout ) ) + { + Debug.LogWarning( "[AmplifyMotion] Aborted abnormally long Async Skin deform operation. Not a critical error but might indicate a problem. Please contact support." ); + return; + } + m_asyncUpdateTriggered = false; + } + } + +#if UNITY_4 + internal override void RenderVectors( Camera camera, float scale, AmplifyMotion.Quality quality ) + { + if ( m_initialized && !m_error && m_renderer.isVisible ) + { + Profiler.BeginSample( "Skinned.Update" ); + + if ( !m_useFallback ) + { + if ( !m_useGPU ) + WaitForAsyncUpdate(); + } + + Profiler.EndSample(); + + Profiler.BeginSample( "Skinned.Render" ); + + if ( !m_useGPU ) + { + if ( !m_useFallback ) + m_clonedMesh.vertices = m_currVertices; + m_clonedMesh.normals = m_prevVertices; + } + + const float rcp255 = 1 / 255.0f; + bool mask = ( m_owner.Instance.CullingMask & ( 1 << m_obj.gameObject.layer ) ) != 0; + int objectId = mask ? m_owner.Instance.GenerateObjectId( m_obj.gameObject ) : 255; + + Matrix4x4 prevModelViewProj; + if ( m_obj.FixedStep ) + prevModelViewProj = m_owner.PrevViewProjMatrixRT * m_currLocalToWorld; + else + prevModelViewProj = m_owner.PrevViewProjMatrixRT * m_prevLocalToWorld; + + Shader.SetGlobalMatrix( "_AM_MATRIX_PREV_MVP", prevModelViewProj ); + Shader.SetGlobalFloat( "_AM_OBJECT_ID", objectId * rcp255 ); + Shader.SetGlobalFloat( "_AM_MOTION_SCALE", mask ? scale : 0 ); + + if ( m_useGPU ) + { + #if !UNITY_4 + Vector4 vertexTexelSize = new Vector4( 1.0f / m_gpuVertexTexWidth, 1.0f / m_gpuVertexTexHeight, m_gpuVertexTexWidth, m_gpuVertexTexHeight ); + + Shader.SetGlobalVector( "_AM_VERTEX_TEXEL_SIZE", vertexTexelSize ); + Shader.SetGlobalVector( "_AM_VERTEX_TEXEL_HALFSIZE", vertexTexelSize * 0.5f ); + + Shader.SetGlobalTexture( "_AM_PREV_VERTEX_TEX", m_gpuPrevVertices ); + Shader.SetGlobalTexture( "_AM_CURR_VERTEX_TEX", m_gpuCurrVertices ); + #endif + } + + int hardwarePass = m_useGPU ? 4 : 0; + int qualityPass = ( quality == AmplifyMotion.Quality.Mobile ) ? 0 : 2; + int basePass = hardwarePass + qualityPass; + + for ( int i = 0; i < m_sharedMaterials.Length; i++ ) + { + MaterialDesc matDesc = m_sharedMaterials[ i ]; + int pass = basePass + ( matDesc.coverage ? 1 : 0 ); + + if ( matDesc.coverage ) + { + m_owner.Instance.SkinnedVectorsMaterial.mainTexture = matDesc.material.mainTexture; + if ( matDesc.cutoff ) + m_owner.Instance.SkinnedVectorsMaterial.SetFloat( "_Cutoff", matDesc.material.GetFloat( "_Cutoff" ) ); + } + + if ( m_owner.Instance.SkinnedVectorsMaterial.SetPass( pass ) ) + Graphics.DrawMeshNow( m_clonedMesh, m_currLocalToWorld, i ); + } + + Profiler.EndSample(); + } + } +#else + internal override void RenderVectors( Camera camera, CommandBuffer renderCB, float scale, AmplifyMotion.Quality quality ) + { + if ( m_initialized && !m_error && m_renderer.isVisible ) + { + Profiler.BeginSample( "Skinned.Update" ); + + if ( !m_useFallback ) + { + if ( !m_useGPU ) + WaitForAsyncUpdate(); + } + + Profiler.EndSample(); + + Profiler.BeginSample( "Skinned.Render" ); + if ( !m_useGPU ) + { + if ( !m_useFallback ) + m_clonedMesh.vertices = m_currVertices; + m_clonedMesh.normals = m_prevVertices; + } + + const float rcp255 = 1 / 255.0f; + bool mask = ( m_owner.Instance.CullingMask & ( 1 << m_obj.gameObject.layer ) ) != 0; + int objectId = mask ? m_owner.Instance.GenerateObjectId( m_obj.gameObject ) : 255; + + Matrix4x4 prevModelViewProj; + if ( m_obj.FixedStep ) + prevModelViewProj = m_owner.PrevViewProjMatrixRT * m_currLocalToWorld; + else + prevModelViewProj = m_owner.PrevViewProjMatrixRT * m_prevLocalToWorld; + + renderCB.SetGlobalMatrix( "_AM_MATRIX_PREV_MVP", prevModelViewProj ); + renderCB.SetGlobalFloat( "_AM_OBJECT_ID", objectId * rcp255 ); + renderCB.SetGlobalFloat( "_AM_MOTION_SCALE", mask ? scale : 0 ); + + if ( m_useGPU ) + { + #if !UNITY_4 + Vector4 vertexTexelSize = new Vector4( 1.0f / m_gpuVertexTexWidth, 1.0f / m_gpuVertexTexHeight, m_gpuVertexTexWidth, m_gpuVertexTexHeight ); + + renderCB.SetGlobalVector( "_AM_VERTEX_TEXEL_SIZE", vertexTexelSize ); + renderCB.SetGlobalVector( "_AM_VERTEX_TEXEL_HALFSIZE", vertexTexelSize * 0.5f ); + + renderCB.SetGlobalTexture( "_AM_PREV_VERTEX_TEX", m_gpuPrevVertices ); + renderCB.SetGlobalTexture( "_AM_CURR_VERTEX_TEX", m_gpuCurrVertices ); + #endif + } + + int hardwarePass = m_useGPU ? 4 : 0; + int qualityPass = ( quality == AmplifyMotion.Quality.Mobile ) ? 0 : 2; + int basePass = hardwarePass + qualityPass; + + for ( int i = 0; i < m_sharedMaterials.Length; i++ ) + { + MaterialDesc matDesc = m_sharedMaterials[ i ]; + int pass = basePass + ( matDesc.coverage ? 1 : 0 ); + + if ( matDesc.coverage ) + { + Texture mainTex = matDesc.material.mainTexture; + if ( mainTex != null ) + matDesc.propertyBlock.SetTexture( "_MainTex", mainTex ); + if ( matDesc.cutoff ) + matDesc.propertyBlock.SetFloat( "_Cutoff", matDesc.material.GetFloat( "_Cutoff" ) ); + } + + renderCB.DrawMesh( m_clonedMesh, m_currLocalToWorld, m_owner.Instance.SkinnedVectorsMaterial, i, pass, matDesc.propertyBlock ); + } + + Profiler.EndSample(); + } + } +#endif + + //internal override void RenderDebugHUD() + //{ + // if ( m_useGPU && m_obj.name.Contains( "Soldier" ) ) + // { + // const int size = 180; + // int y = 180; + // + // GUI.DrawTexture( new Rect( 0, y, size, size ), m_gpuBoneIndices, ScaleMode.ScaleToFit, false ); + // GUI.DrawTexture( new Rect( size * 2, y, size, size ), m_gpuBones, ScaleMode.ScaleToFit, false ); + // y += size + 10; + // + // for ( int w = 0; w < m_weightCount; w++ ) + // GUI.DrawTexture( new Rect( w * size, y, size, size ), m_gpuBaseVertices[ w ], ScaleMode.ScaleToFit, false ); + // + // GUI.DrawTexture( new Rect( Screen.width - size * 2, y, size, size ), m_gpuPrevVertices, ScaleMode.ScaleToFit, false ); + // GUI.DrawTexture( new Rect( Screen.width - size, y, size, size ), m_gpuCurrVertices, ScaleMode.ScaleToFit, false ); + // } + //} +} +} diff --git a/Assets/Cinematic Effects/MotionBlur/Plugins/SkinnedState.cs.meta b/Assets/Cinematic Effects/MotionBlur/Plugins/SkinnedState.cs.meta new file mode 100644 index 0000000..9638c1b --- /dev/null +++ b/Assets/Cinematic Effects/MotionBlur/Plugins/SkinnedState.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: ef01d8ed1b37f1e4db5c9d687dc4b0dd +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/MotionBlur/Plugins/SolidState.cs b/Assets/Cinematic Effects/MotionBlur/Plugins/SolidState.cs new file mode 100644 index 0000000..87179c5 --- /dev/null +++ b/Assets/Cinematic Effects/MotionBlur/Plugins/SolidState.cs @@ -0,0 +1,212 @@ +// Amplify Motion - Full-scene Motion Blur for Unity Pro +// Copyright (c) Amplify Creations, Lda + +#if UNITY_4_0 || UNITY_4_1 || UNITY_4_2 || UNITY_4_3 || UNITY_4_4 || UNITY_4_5 || UNITY_4_6 || UNITY_4_7 || UNITY_4_8 || UNITY_4_9 +#define UNITY_4 +#endif +#if UNITY_5_0 || UNITY_5_1 || UNITY_5_2 || UNITY_5_3 || UNITY_5_4 || UNITY_5_5 || UNITY_5_6 || UNITY_5_7 || UNITY_5_8 || UNITY_5_9 +#define UNITY_5 +#endif + +using System; +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.Profiling; +#if !UNITY_4 +using UnityEngine.Rendering; +#endif + +namespace AmplifyMotion +{ +internal class SolidState : AmplifyMotion.MotionState +{ + public MeshRenderer m_meshRenderer; + + public Matrix4x4 m_prevLocalToWorld; + public Matrix4x4 m_currLocalToWorld; + + public Vector3 m_lastPosition; + public Quaternion m_lastRotation; + public Vector3 m_lastScale; + + private Mesh m_mesh; + + private MaterialDesc[] m_sharedMaterials; + + public bool m_moved = false; + private bool m_wasVisible; + + private static HashSet m_uniqueWarnings = new HashSet(); + + public SolidState( AmplifyMotionCamera owner, AmplifyMotionObjectBase obj ) + : base( owner, obj ) + { + m_meshRenderer = m_obj.GetComponent(); + } + + internal override void Initialize() + { + MeshFilter meshFilter = m_obj.GetComponent(); + if ( meshFilter == null || meshFilter.mesh == null ) + { + if ( !m_uniqueWarnings.Contains( m_obj ) ) + { + Debug.LogWarning( "[AmplifyMotion] Invalid MeshFilter/Mesh in object " + m_obj.name + ". Skipping." ); + m_uniqueWarnings.Add( m_obj ); + } + m_error = true; + return; + } + + base.Initialize(); + + m_mesh = meshFilter.mesh; + + m_sharedMaterials = ProcessSharedMaterials( m_meshRenderer.sharedMaterials ); + + m_wasVisible = false; + } + +#if UNITY_4 + internal override void UpdateTransform( bool starting ) +#else + internal override void UpdateTransform( CommandBuffer updateCB, bool starting ) +#endif + { + if ( !m_initialized ) + { + Initialize(); + return; + } + + Profiler.BeginSample( "Solid.Update" ); + + if ( !starting && m_wasVisible ) + m_prevLocalToWorld = m_currLocalToWorld; + + m_moved = true; + if ( !m_owner.Overlay ) + { + Vector3 position = m_transform.position; + Quaternion rotation = m_transform.rotation; + Vector3 scale = m_transform.lossyScale; + + m_moved = starting || + VectorChanged( position, m_lastPosition ) || + RotationChanged( rotation, m_lastRotation ) || + VectorChanged( scale, m_lastScale ); + + if ( m_moved ) + { + m_lastPosition = position; + m_lastRotation = rotation; + m_lastScale = scale; + } + } + + m_currLocalToWorld = m_transform.localToWorldMatrix; + + if ( starting || !m_wasVisible ) + m_prevLocalToWorld = m_currLocalToWorld; + + m_wasVisible = m_meshRenderer.isVisible; + + Profiler.EndSample(); + } + +#if UNITY_4 + internal override void RenderVectors( Camera camera, float scale, AmplifyMotion.Quality quality ) + { + if ( m_initialized && !m_error && m_meshRenderer.isVisible ) + { + Profiler.BeginSample( "Solid.Render" ); + + bool mask = ( m_owner.Instance.CullingMask & ( 1 << m_obj.gameObject.layer ) ) != 0; + if ( !mask || ( mask && m_moved ) ) + { + const float rcp255 = 1 / 255.0f; + int objectId = mask ? m_owner.Instance.GenerateObjectId( m_obj.gameObject ) : 255; + + Matrix4x4 prevModelViewProj; + if ( m_obj.FixedStep ) + prevModelViewProj = m_owner.PrevViewProjMatrixRT * m_currLocalToWorld; + else + prevModelViewProj = m_owner.PrevViewProjMatrixRT * m_prevLocalToWorld; + + Shader.SetGlobalMatrix( "_AM_MATRIX_PREV_MVP", prevModelViewProj ); + Shader.SetGlobalFloat( "_AM_OBJECT_ID", objectId * rcp255 ); + Shader.SetGlobalFloat( "_AM_MOTION_SCALE", mask ? scale : 0 ); + + int qualityPass = ( quality == AmplifyMotion.Quality.Mobile ) ? 0 : 2; + + for ( int i = 0; i < m_sharedMaterials.Length; i++ ) + { + MaterialDesc matDesc = m_sharedMaterials[ i ]; + int pass = qualityPass + ( matDesc.coverage ? 1 : 0 ); + + if ( matDesc.coverage ) + { + m_owner.Instance.SolidVectorsMaterial.mainTexture = matDesc.material.mainTexture; + if ( matDesc.cutoff ) + m_owner.Instance.SolidVectorsMaterial.SetFloat( "_Cutoff", matDesc.material.GetFloat( "_Cutoff" ) ); + } + + if ( m_owner.Instance.SolidVectorsMaterial.SetPass( pass ) ) + Graphics.DrawMeshNow( m_mesh, m_transform.localToWorldMatrix, i ); + } + } + + Profiler.EndSample(); + } + } +#else + internal override void RenderVectors( Camera camera, CommandBuffer renderCB, float scale, AmplifyMotion.Quality quality ) + { + if ( m_initialized && !m_error && m_meshRenderer.isVisible ) + { + Profiler.BeginSample( "Solid.Render" ); + + bool mask = ( m_owner.Instance.CullingMask & ( 1 << m_obj.gameObject.layer ) ) != 0; + if ( !mask || ( mask && m_moved ) ) + { + const float rcp255 = 1 / 255.0f; + int objectId = mask ? m_owner.Instance.GenerateObjectId( m_obj.gameObject ) : 255; + + Matrix4x4 prevModelViewProj; + if ( m_obj.FixedStep ) + prevModelViewProj = m_owner.PrevViewProjMatrixRT * m_currLocalToWorld; + else + prevModelViewProj = m_owner.PrevViewProjMatrixRT * m_prevLocalToWorld; + + renderCB.SetGlobalMatrix( "_AM_MATRIX_PREV_MVP", prevModelViewProj ); + renderCB.SetGlobalFloat( "_AM_OBJECT_ID", objectId * rcp255 ); + renderCB.SetGlobalFloat( "_AM_MOTION_SCALE", mask ? scale : 0 ); + + // TODO: cache property blocks + + int qualityPass = ( quality == AmplifyMotion.Quality.Mobile ) ? 0 : 2; + + for ( int i = 0; i < m_sharedMaterials.Length; i++ ) + { + MaterialDesc matDesc = m_sharedMaterials[ i ]; + int pass = qualityPass + ( matDesc.coverage ? 1 : 0 ); + + if ( matDesc.coverage ) + { + Texture mainTex = matDesc.material.mainTexture; + if ( mainTex != null ) + matDesc.propertyBlock.SetTexture( "_MainTex", mainTex ); + if ( matDesc.cutoff ) + matDesc.propertyBlock.SetFloat( "_Cutoff", matDesc.material.GetFloat( "_Cutoff" ) ); + } + + renderCB.DrawMesh( m_mesh, m_transform.localToWorldMatrix, m_owner.Instance.SolidVectorsMaterial, i, pass, matDesc.propertyBlock ); + } + } + + Profiler.EndSample(); + } + } +#endif +} +} diff --git a/Assets/Cinematic Effects/MotionBlur/Plugins/SolidState.cs.meta b/Assets/Cinematic Effects/MotionBlur/Plugins/SolidState.cs.meta new file mode 100644 index 0000000..dd70ecb --- /dev/null +++ b/Assets/Cinematic Effects/MotionBlur/Plugins/SolidState.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 9d29ecb1177dbe5488d7d41e2fa8ef6a +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/MotionBlur/Plugins/WorkerThreadPool.cs b/Assets/Cinematic Effects/MotionBlur/Plugins/WorkerThreadPool.cs new file mode 100644 index 0000000..7491b16 --- /dev/null +++ b/Assets/Cinematic Effects/MotionBlur/Plugins/WorkerThreadPool.cs @@ -0,0 +1,182 @@ +// Amplify Motion - Full-scene Motion Blur for Unity Pro +// Copyright (c) Amplify Creations, Lda + +using System; +using System.Threading; +#if NETFX_CORE +using Windows.System.Threading; +using System.Threading.Tasks; +#endif +using System.Collections.Generic; +using UnityEngine; + +namespace AmplifyMotion +{ +internal class WorkerThreadPool +{ +#if !NETFX_CORE && !UNITY_WEBGL + private const int ThreadStateQueueCapacity = 1024; + internal Queue[] m_threadStateQueues = null; + internal object[] m_threadStateQueueLocks = null; + + private int m_threadPoolSize = 0; + private ManualResetEvent m_threadPoolTerminateSignal; + private AutoResetEvent[] m_threadPoolContinueSignals; + private Thread[] m_threadPool = null; + private bool m_threadPoolFallback = false; + internal object m_threadPoolLock = null; + internal int m_threadPoolIndex = 0; +#endif + + internal void InitializeAsyncUpdateThreads( int threadCount, bool systemThreadPool ) + { + #if !NETFX_CORE && !UNITY_WEBGL + if ( systemThreadPool ) + { + m_threadPoolFallback = true; + return; + } + + try + { + m_threadPoolSize = threadCount; + m_threadStateQueues = new Queue[ m_threadPoolSize ]; + m_threadStateQueueLocks = new object[ m_threadPoolSize ]; + m_threadPool = new Thread[ m_threadPoolSize ]; + + m_threadPoolTerminateSignal = new ManualResetEvent( false ); + m_threadPoolContinueSignals = new AutoResetEvent[ m_threadPoolSize ]; + m_threadPoolLock = new object(); + m_threadPoolIndex = 0; + + for ( int id = 0; id < m_threadPoolSize; id++ ) + { + m_threadStateQueues[ id ] = new Queue( ThreadStateQueueCapacity ); + m_threadStateQueueLocks[ id ] = new object(); + + m_threadPoolContinueSignals[ id ] = new AutoResetEvent( false ); + + m_threadPool[ id ] = new Thread( new ParameterizedThreadStart( AsyncUpdateThread ) ); + m_threadPool[ id ].Start( new KeyValuePair( this, id ) ); + } + } + catch ( Exception e ) + { + // fallback to ThreadPool + Debug.LogWarning( "[AmplifyMotion] Non-critical error while initializing WorkerThreads. Falling back to using System.Threading.ThreadPool().\n" + e.Message ); + m_threadPoolFallback = true; + } + #endif + } + + internal void FinalizeAsyncUpdateThreads() + { + #if !NETFX_CORE && !UNITY_WEBGL + if ( !m_threadPoolFallback ) + { + m_threadPoolTerminateSignal.Set(); + + for ( int i = 0; i < m_threadPoolSize; i++ ) + { + if ( m_threadPool[ i ].IsAlive ) + { + m_threadPoolContinueSignals[ i ].Set(); + m_threadPool[ i ].Join(); + + // making sure these marked for disposal + m_threadPool[ i ] = null; + } + + lock ( m_threadStateQueueLocks[ i ] ) + { + while ( m_threadStateQueues[ i ].Count > 0 ) + m_threadStateQueues[ i ].Dequeue().AsyncUpdate(); + } + } + + m_threadStateQueues = null; + m_threadStateQueueLocks = null; + + m_threadPoolSize = 0; + m_threadPool = null; + m_threadPoolTerminateSignal = null; + m_threadPoolContinueSignals = null; + m_threadPoolLock = null; + m_threadPoolIndex = 0; + } + #endif + } + + internal void EnqueueAsyncUpdate( AmplifyMotion.MotionState state ) + { + #if NETFX_CORE + Task.Run( () => AsyncUpdateCallback( state ) ); + #elif UNITY_WEBGL + AsyncUpdateCallback( state ); + #else + if ( !m_threadPoolFallback ) + { + lock ( m_threadStateQueueLocks[ m_threadPoolIndex ] ) + { + m_threadStateQueues[ m_threadPoolIndex ].Enqueue( state ); + } + + m_threadPoolContinueSignals[ m_threadPoolIndex ].Set(); + + m_threadPoolIndex++; + if ( m_threadPoolIndex >= m_threadPoolSize ) + m_threadPoolIndex = 0; + } + else + ThreadPool.QueueUserWorkItem( new WaitCallback( AsyncUpdateCallback ), state ); + #endif + } + + private static void AsyncUpdateCallback( object obj ) + { + AmplifyMotion.MotionState state = ( AmplifyMotion.MotionState ) obj; + state.AsyncUpdate(); + } + + private static void AsyncUpdateThread( object obj ) + { + #if !NETFX_CORE && !UNITY_WEBGL + KeyValuePair pair = ( KeyValuePair ) obj; + WorkerThreadPool pool = ( WorkerThreadPool ) pair.Key; + int id = ( int ) pair.Value; + + while ( true ) + { + try + { + pool.m_threadPoolContinueSignals[ id ].WaitOne(); + + if ( pool.m_threadPoolTerminateSignal.WaitOne( 0 ) ) + break; + + while ( true ) + { + AmplifyMotion.MotionState state = null; + + lock ( pool.m_threadStateQueueLocks[ id ] ) + { + if ( pool.m_threadStateQueues[ id ].Count > 0 ) + state = pool.m_threadStateQueues[ id ].Dequeue(); + } + + if ( state != null ) + state.AsyncUpdate(); + else + break; + } + } + catch ( System.Exception e ) + { + if ( e.GetType() != typeof( ThreadAbortException ) ) + Debug.LogWarning( e ); + } + } + #endif + } +} +} diff --git a/Assets/Cinematic Effects/MotionBlur/Plugins/WorkerThreadPool.cs.meta b/Assets/Cinematic Effects/MotionBlur/Plugins/WorkerThreadPool.cs.meta new file mode 100644 index 0000000..5c14588 --- /dev/null +++ b/Assets/Cinematic Effects/MotionBlur/Plugins/WorkerThreadPool.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 657ea4a21f9ed6849b837ac500e921a0 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/MotionBlur/Resources.meta b/Assets/Cinematic Effects/MotionBlur/Resources.meta new file mode 100644 index 0000000..299f9ad --- /dev/null +++ b/Assets/Cinematic Effects/MotionBlur/Resources.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: f9e2a8bd9fe5044ac862ed1d017d8ccc +folderAsset: yes +timeCreated: 1461976949 +licenseType: Pro +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/MotionBlur/Resources/ClothVectors.shader b/Assets/Cinematic Effects/MotionBlur/Resources/ClothVectors.shader new file mode 100644 index 0000000..60e3b7d --- /dev/null +++ b/Assets/Cinematic Effects/MotionBlur/Resources/ClothVectors.shader @@ -0,0 +1,126 @@ +// Amplify Motion - Full-scene Motion Blur for Unity Pro +// Copyright (c) Amplify Creations, Lda + +Shader "Hidden/Amplify Motion/ClothVectors" { + Properties { + _MainTex ("Base (RGB)", 2D) = "white" {} + _Cutoff ("Alpha cutoff", Range(0,1)) = 0.25 + } + CGINCLUDE + #pragma fragmentoption ARB_precision_hint_fastest + #include "Shared.cginc" + + struct appdata_t + { + float4 vertex : POSITION; + float3 prev_vertex : NORMAL; + float2 texcoord : TEXCOORD0; + }; + + struct v2f + { + float4 pos : SV_POSITION; + float4 motion : TEXCOORD0; + float4 screen_pos : TEXCOORD1; + float2 uv : TEXCOORD2; + }; + + sampler2D _MainTex; + float4 _MainTex_ST; + float _Cutoff; + + v2f vert_base( appdata_t v, bool mobile ) + { + v2f o; + UNITY_INITIALIZE_OUTPUT( v2f, o ); + + float4 pos = o.pos = mul( UNITY_MATRIX_MVP, v.vertex ); + float4 pos_prev = mul( _AM_MATRIX_PREV_MVP, float4( v.prev_vertex, 1 ) ); + float4 pos_curr = o.pos; + + #if UNITY_UV_STARTS_AT_TOP + pos_curr.y = -pos_curr.y; + pos_prev.y = -pos_prev.y; + if ( _ProjectionParams.x > 0 ) + pos.y = -pos.y; + #endif + + pos_prev = pos_prev / pos_prev.w; + pos_curr = pos_curr / pos_curr.w; + + if ( mobile ) + o.motion = DeformableMotionVector( ( pos_curr.xyz - pos_prev.xyz ) * _AM_MOTION_SCALE, _AM_OBJECT_ID ); + else + o.motion.xyz = ( pos_curr.xyz - pos_prev.xyz ) * _AM_MOTION_SCALE; + + o.screen_pos = ComputeScreenPos( pos ); + o.uv = TRANSFORM_TEX( v.texcoord, _MainTex ); + return o; + } + + inline half4 frag_opaque( v2f i, const bool mobile ) + { + if ( !DepthTest( i.screen_pos ) ) + discard; + + if ( mobile ) + return i.motion; + else + return DeformableMotionVector( i.motion, _AM_OBJECT_ID ); + } + + inline half4 frag_cutout( v2f i, const bool mobile ) + { + if ( !DepthTest( i.screen_pos ) || tex2D( _MainTex, i.uv ).a < _Cutoff ) + discard; + + if ( mobile ) + return i.motion; + else + return DeformableMotionVector( i.motion, _AM_OBJECT_ID ); + } + ENDCG + SubShader { + Tags { "RenderType"="Opaque" } + Blend Off Cull Off Fog { Mode off } + ZTest LEqual ZWrite On + Offset -1, -1 + Pass { + Name "MOB_OPAQUE" + CGPROGRAM + #pragma vertex vert + #pragma fragment frag + v2f vert( appdata_t v ) { return vert_base( v, true ); } + half4 frag( v2f v ) : SV_Target { return frag_opaque( v, true ); } + ENDCG + } + Pass { + Name "MOB_CUTOUT" + CGPROGRAM + #pragma vertex vert + #pragma fragment frag + v2f vert( appdata_t v ) { return vert_base( v, true ); } + half4 frag( v2f v ) : SV_Target { return frag_cutout( v, true ); } + ENDCG + } + Pass { + Name "STD_OPAQUE" + CGPROGRAM + #pragma vertex vert + #pragma fragment frag + v2f vert( appdata_t v ) { return vert_base( v, false ); } + half4 frag( v2f v ) : SV_Target { return frag_opaque( v, false ); } + ENDCG + } + Pass { + Name "STD_CUTOUT" + CGPROGRAM + #pragma vertex vert + #pragma fragment frag + v2f vert( appdata_t v ) { return vert_base( v, false ); } + half4 frag( v2f v ) : SV_Target { return frag_cutout( v, false ); } + ENDCG + } + } + FallBack Off +} diff --git a/Assets/Cinematic Effects/MotionBlur/Resources/ClothVectors.shader.meta b/Assets/Cinematic Effects/MotionBlur/Resources/ClothVectors.shader.meta new file mode 100644 index 0000000..9414595 --- /dev/null +++ b/Assets/Cinematic Effects/MotionBlur/Resources/ClothVectors.shader.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 1768f062f9aaadc49b754774fc1c5c47 +ShaderImporter: + defaultTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/MotionBlur/Resources/Combine.shader b/Assets/Cinematic Effects/MotionBlur/Resources/Combine.shader new file mode 100644 index 0000000..8fac628 --- /dev/null +++ b/Assets/Cinematic Effects/MotionBlur/Resources/Combine.shader @@ -0,0 +1,75 @@ +// Amplify Motion - Full-scene Motion Blur for Unity Pro +// Copyright (c) Amplify Creations, Lda + +Shader "Hidden/Amplify Motion/Combine" { + Properties { + _MainTex ("Base (RGB)", 2D) = "white" {} + _MotionTex ("Motion (RGB)", 2D) = "white" {} + _CameraMotionTex ("Motion (RGB)", 2D) = "white" {} + } + CGINCLUDE + #include "UnityCG.cginc" + + sampler2D _MainTex; + sampler2D _MotionTex; + sampler2D _BlurredTex; + float4 _MainTex_TexelSize; + + struct v2f + { + float4 pos : SV_POSITION; + float4 uv : TEXCOORD0; + }; + + v2f vert( appdata_img v ) + { + v2f o; + o.pos = mul( UNITY_MATRIX_MVP, v.vertex ); + o.uv.xy = v.texcoord.xy; + o.uv.zw = v.texcoord.xy; + #if defined( UNITY_UV_STARTS_AT_TOP ) + if ( _MainTex_TexelSize.y < 0 ) + o.uv.w = 1 - o.uv.w; + #endif + return o; + } + ENDCG + SubShader { + ZTest Always Cull Off ZWrite Off Fog { Mode off } + + // Combine source RGB and motion object ID + Pass { + CGPROGRAM + #pragma vertex vert + #pragma fragment frag + #pragma fragmentoption ARB_precision_hint_fastest + #pragma exclude_renderers flash + + half4 frag( v2f i ) : SV_Target + { + return half4( tex2D( _MainTex, i.uv.xy ).xyz, tex2D( _MotionTex, i.uv.zw ).a + 0.0000001f ); // hack to trick Unity into behaving + } + ENDCG + } + + // Combine motion blurred lowres and non-blurred full res (mobile mode) + Pass { + Blend SrcAlpha OneMinusSrcAlpha + CGPROGRAM + #pragma vertex vert + #pragma fragment frag + #pragma fragmentoption ARB_precision_hint_fastest + #pragma exclude_renderers flash + + half4 frag( v2f i ) : SV_Target + { + half4 source = tex2D( _MainTex, i.uv.xy ); + half mag = 2 * tex2D( _MotionTex, i.uv.zw ).z; + return half4( source.rgb, 1 - saturate( mag * 1.5 ) ); + } + ENDCG + } + } + + Fallback Off +} diff --git a/Assets/Cinematic Effects/MotionBlur/Resources/Combine.shader.meta b/Assets/Cinematic Effects/MotionBlur/Resources/Combine.shader.meta new file mode 100644 index 0000000..41d8eb6 --- /dev/null +++ b/Assets/Cinematic Effects/MotionBlur/Resources/Combine.shader.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 930d72fd71d3a464b9ac2e51161a269e +ShaderImporter: + defaultTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/MotionBlur/Resources/Debug.shader b/Assets/Cinematic Effects/MotionBlur/Resources/Debug.shader new file mode 100644 index 0000000..16f8a44 --- /dev/null +++ b/Assets/Cinematic Effects/MotionBlur/Resources/Debug.shader @@ -0,0 +1,56 @@ +// Amplify Motion - Full-scene Motion Blur for Unity Pro +// Copyright (c) Amplify Creations, Lda + +Shader "Hidden/Amplify Motion/Debug" { + Properties { + _MainTex ("Base (RGB)", 2D) = "white" {} + _MotionTex ("Motion (RGB)", 2D) = "white" {} + } + SubShader { + Pass { + ZTest Always Cull Off ZWrite Off Fog { Mode off } + + CGPROGRAM + #pragma vertex vert + #pragma fragment frag + #pragma fragmentoption ARB_precision_hint_fastest + #pragma exclude_renderers flash + #include "UnityCG.cginc" + + sampler2D _MainTex; + sampler2D _MotionTex; + sampler2D _CameraDepthTexture; + float4 _MainTex_TexelSize; + + struct v2f + { + float4 pos : SV_POSITION; + float4 uv : TEXCOORD0; + }; + + v2f vert( appdata_img v ) + { + v2f o; + o.pos = mul( UNITY_MATRIX_MVP, v.vertex ); + o.uv.xy = v.texcoord.xy; + o.uv.zw = v.texcoord.xy; + #if UNITY_UV_STARTS_AT_TOP + if ( _MainTex_TexelSize.y < 0 ) + o.uv.w = 1 - o.uv.w; + #endif + return o; + } + + half4 frag( v2f i ) : SV_Target + { + half4 motion = tex2D( _MotionTex, i.uv.zw ); + half2 vec = ( motion.xy * 2 - 1 ) * motion.z; + half id = motion.w; + return half4( vec, id * 10, 1 ); + } + ENDCG + } + } + + Fallback Off +} diff --git a/Assets/Cinematic Effects/MotionBlur/Resources/Debug.shader.meta b/Assets/Cinematic Effects/MotionBlur/Resources/Debug.shader.meta new file mode 100644 index 0000000..ba1d73b --- /dev/null +++ b/Assets/Cinematic Effects/MotionBlur/Resources/Debug.shader.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: e352ad1d36bf8904c927cfbcecf998d1 +ShaderImporter: + defaultTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/MotionBlur/Resources/Depth.shader b/Assets/Cinematic Effects/MotionBlur/Resources/Depth.shader new file mode 100644 index 0000000..8c51fa6 --- /dev/null +++ b/Assets/Cinematic Effects/MotionBlur/Resources/Depth.shader @@ -0,0 +1,139 @@ +// Amplify Motion - Full-scene Motion Blur for Unity Pro +// Copyright (c) Amplify Creations, Lda + +Shader "Hidden/Amplify Motion/Depth" { + Properties { + _MainTex ("Base (RGB)", 2D) = "white" {} + _MotionTex ("Motion (RGB)", 2D) = "white" {} + } + CGINCLUDE + #pragma fragmentoption ARB_precision_hint_fastest + #pragma exclude_renderers flash + #include "UnityCG.cginc" + + sampler2D _CameraDepthTexture; + float4 _CameraDepthTexture_TexelSize; + + sampler2D _MainTex; + float4 _MainTex_TexelSize; + + sampler2D _MotionTex; + + struct v2f + { + float4 pos : SV_POSITION; + float4 uv : TEXCOORD0; + float4 uv0 : TEXCOORD1; + float4 uv1 : TEXCOORD2; + float4 uv2 : TEXCOORD3; + float4 uv3 : TEXCOORD4; + }; + + v2f vert( appdata_img v ) + { + v2f o; + o.pos = mul( UNITY_MATRIX_MVP, v.vertex ); + + const float4 texels = float4( _MainTex_TexelSize.xy, _CameraDepthTexture_TexelSize.xy ); + const float4 offsets[ 4 ] = { + float4( 0.5, 0.5, 0.5, 0.5 ), + float4( 1.5, 0.5, 1.5, 0.5 ), + float4( 1.5, 1.5, 1.5, 1.5 ), + float4( 0.5, 1.5, 0.5, 1.5 ) + }; + + o.uv = v.texcoord.xyxy; + o.uv0 = v.texcoord.xyxy + texels * offsets[ 0 ]; + o.uv1 = v.texcoord.xyxy + texels * offsets[ 1 ]; + o.uv2 = v.texcoord.xyxy + texels * offsets[ 2 ]; + o.uv3 = v.texcoord.xyxy + texels * offsets[ 3 ]; + + #if UNITY_UV_STARTS_AT_TOP + if ( _MainTex_TexelSize.y < 0 ) + { + o.uv.w = 1 - o.uv.w; + o.uv0.w = 1 - o.uv0.w; + o.uv1.w = 1 - o.uv1.w; + o.uv2.w = 1 - o.uv2.w; + o.uv3.w = 1 - o.uv3.w; + } + #endif + return o; + } + ENDCG + SubShader { + ZTest Always Cull Off ZWrite Off Fog { Mode off } + + // Straight Copy + Pass { + CGPROGRAM + #pragma vertex vert + #pragma fragment frag + + fixed4 frag( v2f i ) : SV_Target + { + float depth = SAMPLE_DEPTH_TEXTURE( _CameraDepthTexture, i.uv.zw ); + return ( depth == 1.0 ) ? ( 1.0 ).xxxx : EncodeFloatRGBA( depth ); + } + ENDCG + } + + // 4-Tap MinZ Depth Downsampling + Pass { + CGPROGRAM + #pragma vertex vert + #pragma fragment frag + + half4 frag( v2f i ) : SV_Target + { + float depth0 = SAMPLE_DEPTH_TEXTURE( _CameraDepthTexture, i.uv0.zw ); + float depth1 = SAMPLE_DEPTH_TEXTURE( _CameraDepthTexture, i.uv1.zw ); + float depth2 = SAMPLE_DEPTH_TEXTURE( _CameraDepthTexture, i.uv2.zw ); + float depth3 = SAMPLE_DEPTH_TEXTURE( _CameraDepthTexture, i.uv3.zw ); + + float depth = depth0; + depth = ( depth1 < depth ) ? depth1 : depth; + depth = ( depth2 < depth ) ? depth2 : depth; + depth = ( depth3 < depth ) ? depth3 : depth; + + return depth.xxxx; + } + ENDCG + } + + // 4-Tap Depth-Aware (MinZ) Combined Downsampling + Pass { + CGPROGRAM + #pragma vertex vert + #pragma fragment frag + + half4 frag( v2f i ) : SV_Target + { + float depth0 = SAMPLE_DEPTH_TEXTURE( _CameraDepthTexture, i.uv0.zw ); + float depth1 = SAMPLE_DEPTH_TEXTURE( _CameraDepthTexture, i.uv1.zw ); + float depth2 = SAMPLE_DEPTH_TEXTURE( _CameraDepthTexture, i.uv2.zw ); + float depth3 = SAMPLE_DEPTH_TEXTURE( _CameraDepthTexture, i.uv3.zw ); + + half4 combo0 = half4( tex2D( _MainTex, i.uv0.xy ).xyz, tex2D( _MotionTex, i.uv0.zw ).a + 0.0000001 ); + half4 combo1 = half4( tex2D( _MainTex, i.uv1.xy ).xyz, tex2D( _MotionTex, i.uv1.zw ).a + 0.0000001 ); + half4 combo2 = half4( tex2D( _MainTex, i.uv2.xy ).xyz, tex2D( _MotionTex, i.uv2.zw ).a + 0.0000001 ); + half4 combo3 = half4( tex2D( _MainTex, i.uv3.xy ).xyz, tex2D( _MotionTex, i.uv3.zw ).a + 0.0000001 ); + + half4 combo = combo0; + float depth = depth0; + + combo = ( depth1 < depth ) ? combo1 : combo; + depth = ( depth1 < depth ) ? depth1 : depth; + combo = ( depth2 < depth ) ? combo2 : combo; + depth = ( depth2 < depth ) ? depth2 : depth; + combo = ( depth3 < depth ) ? combo3 : combo; + depth = ( depth3 < depth ) ? depth3 : depth; + + return combo; + } + ENDCG + } + } + + Fallback Off +} diff --git a/Assets/Cinematic Effects/MotionBlur/Resources/Depth.shader.meta b/Assets/Cinematic Effects/MotionBlur/Resources/Depth.shader.meta new file mode 100644 index 0000000..f1d5439 --- /dev/null +++ b/Assets/Cinematic Effects/MotionBlur/Resources/Depth.shader.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 6e53249b629741a4eb9dc58c3f2b617d +ShaderImporter: + defaultTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/MotionBlur/Resources/Dilation.shader b/Assets/Cinematic Effects/MotionBlur/Resources/Dilation.shader new file mode 100644 index 0000000..447f9ee --- /dev/null +++ b/Assets/Cinematic Effects/MotionBlur/Resources/Dilation.shader @@ -0,0 +1,160 @@ +// Amplify Motion - Full-scene Motion Blur for Unity Pro +// Copyright (c) Amplify Creations, Lda + +Shader "Hidden/Amplify Motion/Dilation" { + Properties { + _MainTex ("Base (RGB)", 2D) = "white" {} + _MotionTex ("Motion (RGB)", 2D) = "white" {} + } + CGINCLUDE + #pragma fragmentoption ARB_precision_hint_fastest + #pragma exclude_renderers flash + #include "UnityCG.cginc" + + sampler2D _CameraDepthTexture; + sampler2D _MotionTex; + float4 _MainTex_TexelSize; + + struct v2f + { + float4 pos : SV_POSITION; + float4 uv : TEXCOORD0; + }; + + v2f vert( appdata_img v ) + { + v2f o; + o.pos = mul( UNITY_MATRIX_MVP, v.vertex ); + o.uv.xy = v.texcoord.xy; + o.uv.zw = v.texcoord.xy; + #if UNITY_UV_STARTS_AT_TOP + if ( _MainTex_TexelSize.y < 0 ) + o.uv.w = 1 - o.uv.w; + #endif + return o; + } + ENDCG + SubShader { + ZTest Always Cull Off ZWrite Off Fog { Mode off } + + // Separable Dilation - 3-Tap Horizontal + Pass { + CGPROGRAM + #pragma vertex vert + #pragma fragment frag_horizontal + + half4 frag_horizontal( v2f i ) : SV_Target + { + float tx = _MainTex_TexelSize.x; + float2 offsets[ 3 ] = { float2( -tx, 0 ), float2( 0, 0 ), float2( tx, 0 ) }; + + half4 motion_ref = tex2D( _MotionTex, i.uv.zw ); + float depth_ref = SAMPLE_DEPTH_TEXTURE( _CameraDepthTexture, i.uv.zw ); + half4 result = motion_ref; + + for ( int tap = 0; tap < 3; tap++ ) + { + float2 tap_uv = i.uv.zw + offsets[ tap ]; + + half4 motion = tex2D( _MotionTex, tap_uv ); + float depth = SAMPLE_DEPTH_TEXTURE( _CameraDepthTexture, tap_uv ); + result = ( depth < depth_ref ) ? motion : result; + } + + return result; + } + ENDCG + } + + // Separable Dilation - 3-Tap Vertical + Pass { + CGPROGRAM + #pragma vertex vert + #pragma fragment frag_vertical + + half4 frag_vertical( v2f i ) : SV_Target + { + float ty = _MainTex_TexelSize.y; + float2 offsets[ 3 ] = { float2( 0, -ty ), float2( 0, 0 ), float2( 0, ty ) }; + + half4 motion_ref = tex2D( _MotionTex, i.uv.zw ); + float depth_ref = SAMPLE_DEPTH_TEXTURE( _CameraDepthTexture, i.uv.zw ); + half4 result = motion_ref; + + for ( int tap = 0; tap < 3; tap++ ) + { + float2 tap_uv = i.uv.zw + offsets[ tap ]; + + half4 motion = tex2D( _MotionTex, tap_uv ); + float depth = SAMPLE_DEPTH_TEXTURE( _CameraDepthTexture, tap_uv ); + result = ( depth < depth_ref ) ? motion : result; + } + + return result; + } + ENDCG + } + + // Separable Dilation - 5-Tap Horizontal + Pass { + CGPROGRAM + #pragma vertex vert + #pragma fragment frag_horizontal + + half4 frag_horizontal( v2f i ) : SV_Target + { + float tx1 = _MainTex_TexelSize.x; + float tx2 = tx1 + tx1; + float2 offsets[ 5 ] = { float2( -tx2, 0 ), float2( -tx1, 0 ), float2( 0, 0 ), float2( tx1, 0 ), float2( tx2, 0 ) }; + + half4 motion_ref = tex2D( _MotionTex, i.uv.zw ); + float depth_ref = SAMPLE_DEPTH_TEXTURE( _CameraDepthTexture, i.uv.zw ); + half4 result = motion_ref; + + for ( int tap = 0; tap < 5; tap++ ) + { + float2 tap_uv = i.uv.zw + offsets[ tap ]; + + half4 motion = tex2D( _MotionTex, tap_uv ); + float depth = SAMPLE_DEPTH_TEXTURE( _CameraDepthTexture, tap_uv ); + result = ( depth < depth_ref ) ? motion : result; + } + + return result; + } + ENDCG + } + + // Separable Dilation - 5-Tap Vertical + Pass { + CGPROGRAM + #pragma vertex vert + #pragma fragment frag_vertical + + half4 frag_vertical( v2f i ) : SV_Target + { + float ty1 = _MainTex_TexelSize.y; + float ty2 = ty1 + ty1; + float2 offsets[ 5 ] = { float2( 0, -ty2 ), float2( 0, -ty1 ), float2( 0, 0 ), float2( 0, ty1 ), float2( 0, ty2 ) }; + + half4 motion_ref = tex2D( _MotionTex, i.uv.zw ); + float depth_ref = SAMPLE_DEPTH_TEXTURE( _CameraDepthTexture, i.uv.zw ); + half4 result = motion_ref; + + for ( int tap = 0; tap < 5; tap++ ) + { + float2 tap_uv = i.uv.zw + offsets[ tap ]; + + half4 motion = tex2D( _MotionTex, tap_uv ); + float depth = SAMPLE_DEPTH_TEXTURE( _CameraDepthTexture, tap_uv ); + result = ( depth < depth_ref ) ? motion : result; + } + + return result; + } + ENDCG + } + } + + Fallback Off +} diff --git a/Assets/Cinematic Effects/MotionBlur/Resources/Dilation.shader.meta b/Assets/Cinematic Effects/MotionBlur/Resources/Dilation.shader.meta new file mode 100644 index 0000000..dadf1af --- /dev/null +++ b/Assets/Cinematic Effects/MotionBlur/Resources/Dilation.shader.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 83053a1495b64ea47942703db953dfb1 +ShaderImporter: + defaultTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/MotionBlur/Resources/GPUSkinDeform.shader b/Assets/Cinematic Effects/MotionBlur/Resources/GPUSkinDeform.shader new file mode 100644 index 0000000..654fec2 --- /dev/null +++ b/Assets/Cinematic Effects/MotionBlur/Resources/GPUSkinDeform.shader @@ -0,0 +1,113 @@ +// Amplify Motion - Full-scene Motion Blur for Unity Pro +// Copyright (c) Amplify Creations, Lda + +Shader "Hidden/Amplify Motion/GPUSkinDeform" { + Properties { } + CGINCLUDE + #pragma target 3.0 + #pragma glsl + #include "UnityCG.cginc" + + sampler2D _AM_BONE_TEX; + sampler2D _AM_BONE_INDEX_TEX; + sampler2D _AM_BASE_VERTEX0_TEX; + sampler2D _AM_BASE_VERTEX1_TEX; + sampler2D _AM_BASE_VERTEX2_TEX; + sampler2D _AM_BASE_VERTEX3_TEX; + + float4 _AM_BONE_TEXEL_SIZE; + float4 _AM_BONE_TEXEL_HALFSIZE; + + float4x4 _AM_WORLD_TO_LOCAL_MATRIX; + + inline float4x4 fetch_bone( float index ) + { + float4 row0 = tex2Dlod( _AM_BONE_TEX, float4( float2( index, 0 ) * _AM_BONE_TEXEL_SIZE.xy + _AM_BONE_TEXEL_HALFSIZE.xy, 0, 0 ) ); + float4 row1 = tex2Dlod( _AM_BONE_TEX, float4( float2( index, 1 ) * _AM_BONE_TEXEL_SIZE.xy + _AM_BONE_TEXEL_HALFSIZE.xy, 0, 0 ) ); + float4 row2 = tex2Dlod( _AM_BONE_TEX, float4( float2( index, 2 ) * _AM_BONE_TEXEL_SIZE.xy + _AM_BONE_TEXEL_HALFSIZE.xy, 0, 0 ) ); + float4 row3 = tex2Dlod( _AM_BONE_TEX, float4( float2( index, 3 ) * _AM_BONE_TEXEL_SIZE.xy + _AM_BONE_TEXEL_HALFSIZE.xy, 0, 0 ) ); + return float4x4( row0, row1, row2, row3 ); + } + ENDCG + SubShader { + ZTest Always Cull Off ZWrite Off Fog { Mode off } + + // 1 weight per-vertex + Pass { + CGPROGRAM + #pragma vertex vert_img + #pragma fragment frag + + float4 frag( v2f_img i ) : SV_Target + { + float4 boneIndices = tex2Dlod( _AM_BONE_INDEX_TEX, float4( i.uv, 0, 0 ) ); + + float4 baseVertex0 = tex2Dlod( _AM_BASE_VERTEX0_TEX, float4( i.uv, 0, 0 ) ); + + float4x4 bone0 = mul( _AM_WORLD_TO_LOCAL_MATRIX, fetch_bone( boneIndices.x ) ); + + float4 deformedVertex; + deformedVertex = mul( bone0, baseVertex0 ); + + return float4( deformedVertex.xyz, 1 ); + } + ENDCG + } + + // 2 weights per-vertex + Pass { + CGPROGRAM + #pragma vertex vert_img + #pragma fragment frag + + float4 frag( v2f_img i ) : SV_Target + { + float4 boneIndices = tex2Dlod( _AM_BONE_INDEX_TEX, float4( i.uv, 0, 0 ) ); + + float4 baseVertex0 = tex2Dlod( _AM_BASE_VERTEX0_TEX, float4( i.uv, 0, 0 ) ); + float4 baseVertex1 = tex2Dlod( _AM_BASE_VERTEX1_TEX, float4( i.uv, 0, 0 ) ); + + float4x4 bone0 = mul( _AM_WORLD_TO_LOCAL_MATRIX, fetch_bone( boneIndices.x ) ); + float4x4 bone1 = mul( _AM_WORLD_TO_LOCAL_MATRIX, fetch_bone( boneIndices.y ) ); + + float4 deformedVertex; + deformedVertex = mul( bone0, baseVertex0 ); + deformedVertex += mul( bone1, baseVertex1 ); + + return float4( deformedVertex.xyz, 1 ); + } + ENDCG + } + + // 4 weights per-vertex + Pass { + CGPROGRAM + #pragma vertex vert_img + #pragma fragment frag + + float4 frag( v2f_img i ) : SV_Target + { + float4 boneIndices = tex2Dlod( _AM_BONE_INDEX_TEX, float4( i.uv, 0, 0 ) ); + + float4 baseVertex0 = tex2Dlod( _AM_BASE_VERTEX0_TEX, float4( i.uv, 0, 0 ) ); + float4 baseVertex1 = tex2Dlod( _AM_BASE_VERTEX1_TEX, float4( i.uv, 0, 0 ) ); + float4 baseVertex2 = tex2Dlod( _AM_BASE_VERTEX2_TEX, float4( i.uv, 0, 0 ) ); + float4 baseVertex3 = tex2Dlod( _AM_BASE_VERTEX3_TEX, float4( i.uv, 0, 0 ) ); + + float4x4 bone0 = mul( _AM_WORLD_TO_LOCAL_MATRIX, fetch_bone( boneIndices.x ) ); + float4x4 bone1 = mul( _AM_WORLD_TO_LOCAL_MATRIX, fetch_bone( boneIndices.y ) ); + float4x4 bone2 = mul( _AM_WORLD_TO_LOCAL_MATRIX, fetch_bone( boneIndices.z ) ); + float4x4 bone3 = mul( _AM_WORLD_TO_LOCAL_MATRIX, fetch_bone( boneIndices.w ) ); + + float4 deformedVertex; + deformedVertex = mul( bone0, baseVertex0 ); + deformedVertex += mul( bone1, baseVertex1 ); + deformedVertex += mul( bone2, baseVertex2 ); + deformedVertex += mul( bone3, baseVertex3 ); + + return float4( deformedVertex.xyz, 1 ); + } + ENDCG + } + } +} diff --git a/Assets/Cinematic Effects/MotionBlur/Resources/GPUSkinDeform.shader.meta b/Assets/Cinematic Effects/MotionBlur/Resources/GPUSkinDeform.shader.meta new file mode 100644 index 0000000..5174a7e --- /dev/null +++ b/Assets/Cinematic Effects/MotionBlur/Resources/GPUSkinDeform.shader.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 9f9650ce6454d854dad8d0372917779e +ShaderImporter: + defaultTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/MotionBlur/Resources/MotionBlurSM2.shader b/Assets/Cinematic Effects/MotionBlur/Resources/MotionBlurSM2.shader new file mode 100644 index 0000000..ee10188 --- /dev/null +++ b/Assets/Cinematic Effects/MotionBlur/Resources/MotionBlurSM2.shader @@ -0,0 +1,35 @@ +// Amplify Motion - Full-scene Motion Blur for Unity Pro +// Copyright (c) Amplify Creations, Lda + +Shader "Hidden/Amplify Motion/MotionBlurSM2" { + Properties { + _MainTex ("Base (RGB)", 2D) = "white" {} + _MotionTex ("Motion (RGB)", 2D) = "white" {} + } + CGINCLUDE + #pragma fragmentoption ARB_precision_hint_fastest + #pragma exclude_renderers flash + + #include "MotionBlurShared.cginc" + ENDCG + SubShader { + ZTest Always Cull Off ZWrite Off Fog { Mode off } + Pass { + Name "MOB" + CGPROGRAM + #pragma vertex vert + #pragma fragment frag_mobile + #pragma target 2.0 + ENDCG + } + Pass { + Name "STD" + CGPROGRAM + #pragma vertex vert + #pragma fragment frag_sm2 + #pragma target 2.0 + ENDCG + } + } + Fallback Off +} diff --git a/Assets/Cinematic Effects/MotionBlur/Resources/MotionBlurSM2.shader.meta b/Assets/Cinematic Effects/MotionBlur/Resources/MotionBlurSM2.shader.meta new file mode 100644 index 0000000..2909ca7 --- /dev/null +++ b/Assets/Cinematic Effects/MotionBlur/Resources/MotionBlurSM2.shader.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: ebf06ea1548615049bfb691bcb60d35b +ShaderImporter: + defaultTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/MotionBlur/Resources/MotionBlurSM3.shader b/Assets/Cinematic Effects/MotionBlur/Resources/MotionBlurSM3.shader new file mode 100644 index 0000000..cf81ccd --- /dev/null +++ b/Assets/Cinematic Effects/MotionBlur/Resources/MotionBlurSM3.shader @@ -0,0 +1,53 @@ +// Amplify Motion - Full-scene Motion Blur for Unity Pro +// Copyright (c) Amplify Creations, Lda + +Shader "Hidden/Amplify Motion/MotionBlurSM3" { + Properties { + _MainTex ("Base (RGB)", 2D) = "white" {} + _MotionTex ("Motion (RGB)", 2D) = "white" {} + } + CGINCLUDE + #pragma fragmentoption ARB_precision_hint_fastest + #pragma exclude_renderers flash + + #include "MotionBlurShared.cginc" + ENDCG + SubShader { + ZTest Always Cull Off ZWrite Off Fog { Mode off } + Pass { + Name "MOB" + CGPROGRAM + #pragma vertex vert + #pragma fragment frag_mobile + #pragma target 2.0 + ENDCG + } + Pass { + Name "STD" + CGPROGRAM + #pragma vertex vert + #pragma fragment frag_sm2 + #pragma target 2.0 + ENDCG + } + Pass { + Name "STD_SM3" + CGPROGRAM + #pragma vertex vert + #pragma fragment frag_sm3 + #pragma target 3.0 + #pragma exclude_renderers d3d11_9x + ENDCG + } + Pass { + Name "SOFT_SM3" + CGPROGRAM + #pragma vertex vert + #pragma fragment frag_soft_sm3 + #pragma target 3.0 + #pragma exclude_renderers d3d11_9x + ENDCG + } + } + Fallback Off +} diff --git a/Assets/Cinematic Effects/MotionBlur/Resources/MotionBlurSM3.shader.meta b/Assets/Cinematic Effects/MotionBlur/Resources/MotionBlurSM3.shader.meta new file mode 100644 index 0000000..cb68c00 --- /dev/null +++ b/Assets/Cinematic Effects/MotionBlur/Resources/MotionBlurSM3.shader.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: b9e697d6188428a43830f6aad3d2c114 +ShaderImporter: + defaultTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/MotionBlur/Resources/MotionBlurShared.cginc b/Assets/Cinematic Effects/MotionBlur/Resources/MotionBlurShared.cginc new file mode 100644 index 0000000..8c2eaf3 --- /dev/null +++ b/Assets/Cinematic Effects/MotionBlur/Resources/MotionBlurShared.cginc @@ -0,0 +1,236 @@ +// Amplify Motion - Full-scene Motion Blur for Unity Pro +// Copyright (c) Amplify Creations, Lda + +#ifndef AMPLIFY_MOTION_BLUR_SHARED_INCLUDED +#define AMPLIFY_MOTION_BLUR_SHARED_INCLUDED + +#include "UnityCG.cginc" + +sampler2D _MainTex; +float4 _MainTex_TexelSize; + +sampler2D _CameraDepthTexture; +float4 _CameraDepthTexture_TexelSize; + +sampler2D _DepthTex; +float4 _DepthTex_TexelSize; +sampler2D _MotionTex; + +half4 _AM_BLUR_STEP; +half2 _AM_DEPTH_THRESHOLD; + +struct v2f +{ + float4 pos : SV_POSITION; + float4 uv : TEXCOORD0; +}; + +v2f vert( appdata_img v ) +{ + v2f o = ( v2f ) 0; + o.pos = mul( UNITY_MATRIX_MVP, v.vertex ); + o.uv.xy = v.texcoord.xy; + o.uv.zw = v.texcoord.xy; +#if UNITY_UV_STARTS_AT_TOP + if ( _MainTex_TexelSize.y < 0 ) + o.uv.w = 1 - o.uv.w; +#endif + return o; +} + +half4 frag_mobile( v2f i ) : SV_Target +{ + // 3-TAP + half3 motion = tex2D( _MotionTex, i.uv.zw ).xyz; + half4 color = tex2D( _MainTex, i.uv.xy ); + half4 accum = half4( color.xyz, 1 ); + + half ref_depth = saturate( DecodeFloatRGBA( tex2D( _DepthTex, i.uv.xy ) ) ); + half ref_id = color.a; + + half id = floor( color.a * 255 + 0.5 ); + half ref_isobj = ( id > 1 ) * ( id < 254 ); + + half2 dir_step = _AM_BLUR_STEP.xy * ( motion.xy * 2.0 - 1.0 ) * motion.z; + + half sample_depth0 = saturate( DecodeFloatRGBA( tex2D( _DepthTex, i.uv.xy - dir_step ) ) ); + half sample_depth1 = saturate( DecodeFloatRGBA( tex2D( _DepthTex, i.uv.xy + dir_step ) ) ); + + half4 sample_color0 = tex2D( _MainTex, i.uv.xy - dir_step ); + half4 sample_color1 = tex2D( _MainTex, i.uv.xy + dir_step ); + + half2 sample_depth = half2( sample_depth0, sample_depth1 ); + half2 sample_id = half2( sample_color0.a, sample_color1.a ); + + half2 depth_test = sample_depth > ( ref_depth.xx - _AM_DEPTH_THRESHOLD.xx ); + half2 obj_test = ref_isobj.xx * ( sample_id == ref_id.xx ); + + half2 sample_test = saturate( depth_test + obj_test ); + + accum += sample_test.x * half4( sample_color0.xyz, 1 ); + accum += sample_test.y * half4( sample_color1.xyz, 1 ); + + return half4( accum.xyz / accum.w, ref_id ); +} + +half4 frag_sm2( v2f i ) : SV_Target +{ + // 5-TAP + half3 motion = tex2D( _MotionTex, i.uv.zw ).xyz; + half4 color = tex2D( _MainTex, i.uv.xy ); + half4 accum = half4( color.xyz, 1 ); + + half ref_depth = SAMPLE_DEPTH_TEXTURE( _CameraDepthTexture, i.uv.xy ); + half ref_id = color.a; + + half id = floor( color.a * 255 + 0.5 ); + half ref_isobj = ( id > 1 ) * ( id < 254 ); + + half2 dir_step = _AM_BLUR_STEP.xy * ( motion.xy * 2.0 - 1.0 ) * motion.z; + half2 dir_step1 = dir_step * 0.5; + + half sample_depth0 = SAMPLE_DEPTH_TEXTURE( _CameraDepthTexture, i.uv.xy - dir_step ); + half sample_depth1 = SAMPLE_DEPTH_TEXTURE( _CameraDepthTexture, i.uv.xy - dir_step1 ); + half sample_depth2 = SAMPLE_DEPTH_TEXTURE( _CameraDepthTexture, i.uv.xy + dir_step1 ); + half sample_depth3 = SAMPLE_DEPTH_TEXTURE( _CameraDepthTexture, i.uv.xy + dir_step ); + + half4 sample_color0 = tex2D( _MainTex, i.uv.xy - dir_step ); + half4 sample_color1 = tex2D( _MainTex, i.uv.xy - dir_step1 ); + half4 sample_color2 = tex2D( _MainTex, i.uv.xy + dir_step1 ); + half4 sample_color3 = tex2D( _MainTex, i.uv.xy + dir_step ); + + half4 sample_depth = half4( sample_depth0, sample_depth1, sample_depth2, sample_depth3 ); + half4 sample_id = half4( sample_color0.a, sample_color1.a, sample_color2.a, sample_color3.a ); + + half4 depth_test = sample_depth > ( ref_depth.xxxx - _AM_DEPTH_THRESHOLD.xxxx ); + half4 obj_test = ref_isobj.xxxx * ( sample_id == ref_id.xxxx ); + + half4 sample_test = saturate( depth_test + obj_test ); + + accum += sample_test.x * half4( sample_color0.xyz, 1 ); + accum += sample_test.y * half4( sample_color1.xyz, 1 ); + accum += sample_test.z * half4( sample_color2.xyz, 1 ); + accum += sample_test.w * half4( sample_color3.xyz, 1 ); + + return half4( accum.xyz / accum.w, ref_id ); +} + +half4 frag_sm3( v2f i ) : SV_Target +{ + // 9-TAP + half3 motion = tex2D( _MotionTex, i.uv.zw ).xyz; + half4 color = tex2D( _MainTex, i.uv.xy ); + half4 accum = half4( color.xyz, 1 ); + + half ref_depth = SAMPLE_DEPTH_TEXTURE( _CameraDepthTexture, i.uv.xy ); + half ref_id = color.a; + + half id = floor( color.a * 255 + 0.5 ); + half ref_isobj = ( id > 1 ) * ( id < 254 ); + + half2 dir_step = _AM_BLUR_STEP.xy * ( motion.xy * 2.0 - 1.0 ) * motion.z; + half2 dir_step1 = dir_step * 0.75; + half2 dir_step2 = dir_step * 0.50; + half2 dir_step3 = dir_step * 0.25; + + half sample_depth0 = SAMPLE_DEPTH_TEXTURE( _CameraDepthTexture, i.uv.xy - dir_step ); + half sample_depth1 = SAMPLE_DEPTH_TEXTURE( _CameraDepthTexture, i.uv.xy - dir_step1 ); + half sample_depth2 = SAMPLE_DEPTH_TEXTURE( _CameraDepthTexture, i.uv.xy - dir_step2 ); + half sample_depth3 = SAMPLE_DEPTH_TEXTURE( _CameraDepthTexture, i.uv.xy - dir_step3 ); + half sample_depth4 = SAMPLE_DEPTH_TEXTURE( _CameraDepthTexture, i.uv.xy + dir_step3 ); + half sample_depth5 = SAMPLE_DEPTH_TEXTURE( _CameraDepthTexture, i.uv.xy + dir_step2 ); + half sample_depth6 = SAMPLE_DEPTH_TEXTURE( _CameraDepthTexture, i.uv.xy + dir_step1 ); + half sample_depth7 = SAMPLE_DEPTH_TEXTURE( _CameraDepthTexture, i.uv.xy + dir_step ); + + half4 sample_depthA = half4( sample_depth0, sample_depth1, sample_depth2, sample_depth3 ); + half4 sample_depthB = half4( sample_depth4, sample_depth5, sample_depth6, sample_depth7 ); + + half4 diffA = ref_depth.xxxx - sample_depthA; + half4 diffB = ref_depth.xxxx - sample_depthB; + half4 diff_testA = diffA < _AM_DEPTH_THRESHOLD.xxxx; + half4 diff_testB = diffB < _AM_DEPTH_THRESHOLD.xxxx; + half4 sample_testA = diff_testA - diff_testA * saturate( diffA * _AM_DEPTH_THRESHOLD.yyyy ); + half4 sample_testB = diff_testB - diff_testB * saturate( diffB * _AM_DEPTH_THRESHOLD.yyyy ); + + half4 sample_color0 = tex2D( _MainTex, i.uv.xy - dir_step * sample_testA.x ); + half4 sample_color1 = tex2D( _MainTex, i.uv.xy - dir_step1 * sample_testA.y ); + half4 sample_color2 = tex2D( _MainTex, i.uv.xy - dir_step2 * sample_testA.z ); + half4 sample_color3 = tex2D( _MainTex, i.uv.xy - dir_step3 * sample_testA.w ); + half4 sample_color4 = tex2D( _MainTex, i.uv.xy + dir_step3 * sample_testB.x ); + half4 sample_color5 = tex2D( _MainTex, i.uv.xy + dir_step2 * sample_testB.y ); + half4 sample_color6 = tex2D( _MainTex, i.uv.xy + dir_step1 * sample_testB.z ); + half4 sample_color7 = tex2D( _MainTex, i.uv.xy + dir_step * sample_testB.w ); + + half4 sample_idA = half4( sample_color0.a, sample_color1.a, sample_color2.a, sample_color3.a ); + half4 sample_idB = half4( sample_color4.a, sample_color5.a, sample_color6.a, sample_color7.a ); + + half4 obj_testA = ref_isobj.xxxx * ( sample_idA == ref_id.xxxx ); + half4 obj_testB = ref_isobj.xxxx * ( sample_idB == ref_id.xxxx ); + + sample_testA = saturate( sample_testA + obj_testA ); + sample_testB = saturate( sample_testB + obj_testB ); + + accum += sample_testA.x * half4( sample_color0.xyz, 1 ); + accum += sample_testA.y * half4( sample_color1.xyz, 1 ); + accum += sample_testA.z * half4( sample_color2.xyz, 1 ); + accum += sample_testA.w * half4( sample_color3.xyz, 1 ); + accum += sample_testB.x * half4( sample_color4.xyz, 1 ); + accum += sample_testB.y * half4( sample_color5.xyz, 1 ); + accum += sample_testB.z * half4( sample_color6.xyz, 1 ); + accum += sample_testB.w * half4( sample_color7.xyz, 1 ); + + return half4( accum.xyz / accum.w, ref_id ); +} + +half4 frag_soft_sm3( v2f i ) : SV_Target +{ + // 5-TAP + half3 motion = tex2D( _MotionTex, i.uv.zw ).xyz; + half4 color = tex2D( _MainTex, i.uv.xy ); + half4 accum = half4( color.xyz, 1 ); + + half ref_depth = SAMPLE_DEPTH_TEXTURE( _CameraDepthTexture, i.uv.xy ); + half ref_id = color.a; + + half id = floor( color.a * 255 + 0.5 ); + half ref_isobj = ( id > 1 ) * ( id < 254 ); + + half2 dir_step = _AM_BLUR_STEP.xy * ( motion.xy * 2.0 - 1.0 ) * motion.z; + half2 dir_step1 = dir_step * 0.5; + + half sample_depth0 = SAMPLE_DEPTH_TEXTURE( _CameraDepthTexture, i.uv.xy - dir_step ); + half sample_depth1 = SAMPLE_DEPTH_TEXTURE( _CameraDepthTexture, i.uv.xy - dir_step1 ); + half sample_depth2 = SAMPLE_DEPTH_TEXTURE( _CameraDepthTexture, i.uv.xy + dir_step1 ); + half sample_depth3 = SAMPLE_DEPTH_TEXTURE( _CameraDepthTexture, i.uv.xy + dir_step ); + + half4 sample_color0 = tex2D( _MainTex, i.uv.xy - dir_step ); + half4 sample_color1 = tex2D( _MainTex, i.uv.xy - dir_step1 ); + half4 sample_color2 = tex2D( _MainTex, i.uv.xy + dir_step1 ); + half4 sample_color3 = tex2D( _MainTex, i.uv.xy + dir_step ); + + half sample_mag0 = tex2D( _MotionTex, i.uv.xy - dir_step ).z; + half sample_mag1 = tex2D( _MotionTex, i.uv.xy - dir_step1 ).z; + half sample_mag2 = tex2D( _MotionTex, i.uv.xy + dir_step1 ).z; + half sample_mag3 = tex2D( _MotionTex, i.uv.xy + dir_step ).z; + + half4 sample_depth = half4( sample_depth0, sample_depth1, sample_depth2, sample_depth3 ); + half4 sample_id = half4( sample_color0.a, sample_color1.a, sample_color2.a, sample_color3.a ); + half4 sample_mag = half4( sample_mag0, sample_mag1, sample_mag2, sample_mag3 ); + + half4 thres_mag = ( 0.5 ).xxxx; + + half4 depth_test = sample_depth > ( ref_depth.xxxx - _AM_DEPTH_THRESHOLD.xxxx ); + half4 obj_test = ref_isobj.xxxx * ( sample_id == ref_id.xxxx ); + half4 mag_test = sample_mag > thres_mag; + + half4 sample_test = saturate( depth_test + obj_test + mag_test ); + + accum += sample_test.x * half4( sample_color0.xyz, 1 ); + accum += sample_test.y * half4( sample_color1.xyz, 1 ); + accum += sample_test.z * half4( sample_color2.xyz, 1 ); + accum += sample_test.w * half4( sample_color3.xyz, 1 ); + + return half4( accum.xyz / accum.w, ref_id ); +} + +#endif diff --git a/Assets/Cinematic Effects/MotionBlur/Resources/MotionBlurShared.cginc.meta b/Assets/Cinematic Effects/MotionBlur/Resources/MotionBlurShared.cginc.meta new file mode 100644 index 0000000..a75cc0f --- /dev/null +++ b/Assets/Cinematic Effects/MotionBlur/Resources/MotionBlurShared.cginc.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 6df9775b9d7b1b14b818b28c92892dae +ShaderImporter: + defaultTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/MotionBlur/Resources/ReprojectionVectors.shader b/Assets/Cinematic Effects/MotionBlur/Resources/ReprojectionVectors.shader new file mode 100644 index 0000000..16e36f8 --- /dev/null +++ b/Assets/Cinematic Effects/MotionBlur/Resources/ReprojectionVectors.shader @@ -0,0 +1,73 @@ + +Shader "Hidden/Amplify Motion/ReprojectionVectors" { + Properties { + _MainTex ("-", 2D) = "" {} + } + SubShader { + Cull Off ZTest Always ZWrite Off Blend Off Fog { Mode Off } + Pass { + CGPROGRAM + #pragma vertex vert + #pragma fragment frag + #pragma fragmentoption ARB_precision_hint_fastest + #include "UnityCG.cginc" + + struct v2f + { + float4 pos : SV_POSITION; + float2 uv : TEXCOORD0; + float2 uv_rt : TEXCOORD1; + }; + + sampler2D _CameraDepthTexture; + sampler2D _MainTex; + float4 _MainTex_TexelSize; + + float4x4 _AM_MATRIX_CURR_REPROJ; + float _AM_MOTION_SCALE; + float _AM_MIN_VELOCITY; + float _AM_MAX_VELOCITY; + float _AM_RCP_TOTAL_VELOCITY; + + v2f vert( appdata_img v ) + { + v2f o; + o.pos = mul( UNITY_MATRIX_MVP, v.vertex ); + o.uv = v.texcoord.xy; + o.uv_rt = v.texcoord.xy; + #if UNITY_UV_STARTS_AT_TOP + if ( _MainTex_TexelSize.y < 0 ) + o.uv_rt.y = 1 - o.uv_rt.y; + #endif + return o; + } + + half4 frag( v2f i ) : SV_Target + { + float d = SAMPLE_DEPTH_TEXTURE( _CameraDepthTexture, i.uv_rt ); + #if defined( SHADER_API_OPENGL ) || defined( SHADER_API_GLES ) || defined( SHADER_API_GLES3 ) + float4 pos_curr = float4( float3( i.uv.xy, d ) * 2 - 1, 1 ); + #else + float4 pos_curr = float4( i.uv.xy * 2 - 1, d, 1 ); + #endif + + // 1) unproject to world; 2) reproject into previous ViewProj + float4 pos_prev = mul( _AM_MATRIX_CURR_REPROJ, pos_curr ); + + pos_prev = pos_prev / pos_prev.w; + pos_curr = pos_curr / pos_curr.w; + + half4 motion = ( pos_curr - pos_prev ) * _AM_MOTION_SCALE; + + motion.z = length( motion.xy ); + motion.xy = ( motion.xy / motion.z ) * 0.5f + 0.5f; + motion.z = ( motion.z < _AM_MIN_VELOCITY ) ? 0 : motion.z; + motion.z = max( min( motion.z, _AM_MAX_VELOCITY ) - _AM_MIN_VELOCITY, 0 ) * _AM_RCP_TOTAL_VELOCITY; + + return half4( motion.xyz, 0 ); + } + ENDCG + } + } + FallBack Off +} diff --git a/Assets/Cinematic Effects/MotionBlur/Resources/ReprojectionVectors.shader.meta b/Assets/Cinematic Effects/MotionBlur/Resources/ReprojectionVectors.shader.meta new file mode 100644 index 0000000..cd27c34 --- /dev/null +++ b/Assets/Cinematic Effects/MotionBlur/Resources/ReprojectionVectors.shader.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 7d54d4ac3d05c2246aebc73a9b2dbf66 +ShaderImporter: + defaultTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/MotionBlur/Resources/Shared.cginc b/Assets/Cinematic Effects/MotionBlur/Resources/Shared.cginc new file mode 100644 index 0000000..763db79 --- /dev/null +++ b/Assets/Cinematic Effects/MotionBlur/Resources/Shared.cginc @@ -0,0 +1,59 @@ +// Amplify Motion - Full-scene Motion Blur for Unity Pro +// Copyright (c) Amplify Creations, Lda + +#ifndef AMPLIFY_MOTION_SHARED_INCLUDED +#define AMPLIFY_MOTION_SHARED_INCLUDED + +#include "UnityCG.cginc" + +sampler2D _CameraDepthTexture; +float4x4 _AM_MATRIX_PREV_MVP; +float4 _AM_ZBUFFER_PARAMS; +float _AM_OBJECT_ID; +float _AM_MOTION_SCALE; +float _AM_MIN_VELOCITY; +float _AM_MAX_VELOCITY; +float _AM_RCP_TOTAL_VELOCITY; + +sampler2D _AM_PREV_VERTEX_TEX; +sampler2D _AM_CURR_VERTEX_TEX; + +float4 _AM_VERTEX_TEXEL_SIZE; +float4 _AM_VERTEX_TEXEL_HALFSIZE; + +inline bool DepthTest( float4 screen_pos ) +{ + const float epsilon = 0.001f; + float3 uv = screen_pos.xyz / screen_pos.w; + float behind = SAMPLE_DEPTH_TEXTURE_PROJ( _CameraDepthTexture, screen_pos ); +#if defined( SHADER_API_OPENGL ) || defined( SHADER_API_GLES ) || defined( SHADER_API_GLES3 ) + float front = uv.z * 0.5 + 0.5; +#else + float front = uv.z; +#endif + return ( behind >= front - epsilon ); +} + +inline half4 SolidMotionVector( half4 pos_prev, half4 pos_curr, half obj_id ) +{ + pos_prev = pos_prev / pos_prev.w; + pos_curr = pos_curr / pos_curr.w; + half4 motion = ( pos_curr - pos_prev ) * _AM_MOTION_SCALE; + + motion.z = length( motion.xy ); + motion.xy = ( motion.xy / motion.z ) * 0.5f + 0.5f; + motion.z = ( motion.z < _AM_MIN_VELOCITY ) ? 0 : motion.z; + motion.z = max( min( motion.z, _AM_MAX_VELOCITY ) - _AM_MIN_VELOCITY, 0 ) * _AM_RCP_TOTAL_VELOCITY; + return half4( motion.xyz, obj_id ); +} + +inline half4 DeformableMotionVector( half3 motion, half obj_id ) +{ + motion.z = length( motion.xy ); + motion.xy = ( motion.xy / motion.z ) * 0.5f + 0.5f; + motion.z = ( motion.z < _AM_MIN_VELOCITY ) ? 0 : motion.z; + motion.z = max( min( motion.z, _AM_MAX_VELOCITY ) - _AM_MIN_VELOCITY, 0 ) * _AM_RCP_TOTAL_VELOCITY; + return half4( motion.xyz, obj_id ); +} + +#endif diff --git a/Assets/Cinematic Effects/MotionBlur/Resources/Shared.cginc.meta b/Assets/Cinematic Effects/MotionBlur/Resources/Shared.cginc.meta new file mode 100644 index 0000000..71cac07 --- /dev/null +++ b/Assets/Cinematic Effects/MotionBlur/Resources/Shared.cginc.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: f73e8f36393c28544851bd0262522296 +ShaderImporter: + defaultTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/MotionBlur/Resources/SkinnedVectors.shader b/Assets/Cinematic Effects/MotionBlur/Resources/SkinnedVectors.shader new file mode 100644 index 0000000..aee4a7a --- /dev/null +++ b/Assets/Cinematic Effects/MotionBlur/Resources/SkinnedVectors.shader @@ -0,0 +1,189 @@ +// Amplify Motion - Full-scene Motion Blur for Unity Pro +// Copyright (c) Amplify Creations, Lda + +Shader "Hidden/Amplify Motion/SkinnedVectors" { + Properties { + _MainTex ("Base (RGB)", 2D) = "white" {} + _Cutoff ("Alpha cutoff", Range(0,1)) = 0.25 + } + CGINCLUDE + #include "Shared.cginc" + + struct appdata_t + { + float4 vertex : POSITION; + float3 prev_vertex : NORMAL; + float2 texcoord : TEXCOORD0; + float2 texcoord1 : TEXCOORD1; + }; + + struct v2f + { + float4 pos : SV_POSITION; + float4 motion : TEXCOORD0; + float4 screen_pos : TEXCOORD1; + float2 uv : TEXCOORD2; + }; + + sampler2D _MainTex; + float4 _MainTex_ST; + float _Cutoff; + + inline v2f vert_base( appdata_t v, const bool mobile, const bool gpu ) + { + v2f o; + UNITY_INITIALIZE_OUTPUT( v2f, o ); + + float4 prev_vertex = float4( v.prev_vertex.xyz, 1 ); + float4 curr_vertex = float4( v.vertex.xyz, 1 ); + + #if UNITY_VERSION >= 500 + if ( gpu ) + { + prev_vertex = 0; + curr_vertex *= 0.00000001; // trick compiler into behaving + + float2 indexCoords = v.texcoord1; + prev_vertex += tex2Dlod( _AM_PREV_VERTEX_TEX, float4( indexCoords, 0, 0 ) ); + curr_vertex += tex2Dlod( _AM_CURR_VERTEX_TEX, float4( indexCoords, 0, 0 ) ); + } + #endif + + float4 pos = o.pos = mul( UNITY_MATRIX_MVP, curr_vertex ); + float4 pos_prev = mul( _AM_MATRIX_PREV_MVP, prev_vertex ); + float4 pos_curr = o.pos; + + #if UNITY_UV_STARTS_AT_TOP + pos_curr.y = -pos_curr.y; + pos_prev.y = -pos_prev.y; + if ( _ProjectionParams.x > 0 ) + pos.y = -pos.y; + #endif + + pos_prev = pos_prev / pos_prev.w; + pos_curr = pos_curr / pos_curr.w; + + if ( mobile ) + o.motion = DeformableMotionVector( ( pos_curr.xyz - pos_prev.xyz ) * _AM_MOTION_SCALE, _AM_OBJECT_ID ); + else + o.motion.xyz = ( pos_curr - pos_prev ) * _AM_MOTION_SCALE; + + o.screen_pos = ComputeScreenPos( pos ); + o.uv = TRANSFORM_TEX( v.texcoord, _MainTex ); + return o; + } + + inline half4 frag_opaque( v2f i, const bool mobile ) + { + if ( !DepthTest( i.screen_pos ) ) + discard; + + if ( mobile ) + return i.motion; + else + return DeformableMotionVector( i.motion, _AM_OBJECT_ID ); + } + + inline half4 frag_cutout( v2f i, const bool mobile ) + { + if ( !DepthTest( i.screen_pos ) || tex2D( _MainTex, i.uv ).a < _Cutoff ) + discard; + + if ( mobile ) + return i.motion; + else + return DeformableMotionVector( i.motion, _AM_OBJECT_ID ); + } + ENDCG + SubShader { + Tags { "RenderType"="Opaque" } + Blend Off Cull Off Fog { Mode off } + ZTest LEqual ZWrite On + Offset -1, -1 + + // CPU path + Pass { + Name "MOB_OPAQUE" + CGPROGRAM + #pragma vertex vert + #pragma fragment frag + #pragma target 2.0 + v2f vert( appdata_t v ) { return vert_base( v, true, false ); } + half4 frag( v2f v ) : SV_Target { return frag_opaque( v, true ); } + ENDCG + } + Pass { + Name "MOB_CUTOUT" + CGPROGRAM + #pragma vertex vert + #pragma fragment frag + #pragma target 2.0 + v2f vert( appdata_t v ) { return vert_base( v, true, false ); } + half4 frag( v2f v ) : SV_Target { return frag_cutout( v, true ); } + ENDCG + } + Pass { + Name "STD_OPAQUE" + CGPROGRAM + #pragma vertex vert + #pragma fragment frag + #pragma target 2.0 + v2f vert( appdata_t v ) { return vert_base( v, false, false ); } + half4 frag( v2f v ) : SV_Target { return frag_opaque( v, false ); } + ENDCG + } + Pass { + Name "STD_CUTOUT" + CGPROGRAM + #pragma vertex vert + #pragma fragment frag + #pragma target 2.0 + v2f vert( appdata_t v ) { return vert_base( v, false, false ); } + half4 frag( v2f v ) : SV_Target { return frag_cutout( v, false ); } + ENDCG + } + + // GPU path + Pass { + Name "MOB_OPAQUE" + CGPROGRAM + #pragma vertex vert + #pragma fragment frag + #pragma target 3.0 + v2f vert( appdata_t v ) { return vert_base( v, true, true ); } + half4 frag( v2f v ) : SV_Target { return frag_opaque( v, true ); } + ENDCG + } + Pass { + Name "MOB_CUTOUT" + CGPROGRAM + #pragma vertex vert + #pragma fragment frag + #pragma target 3.0 + v2f vert( appdata_t v ) { return vert_base( v, true, true ); } + half4 frag( v2f v ) : SV_Target { return frag_cutout( v, true ); } + ENDCG + } + Pass { + Name "STD_OPAQUE" + CGPROGRAM + #pragma vertex vert + #pragma fragment frag + #pragma target 3.0 + v2f vert( appdata_t v ) { return vert_base( v, false, true ); } + half4 frag( v2f v ) : SV_Target { return frag_opaque( v, false ); } + ENDCG + } + Pass { + Name "STD_CUTOUT" + CGPROGRAM + #pragma vertex vert + #pragma fragment frag + #pragma target 3.0 + v2f vert( appdata_t v ) { return vert_base( v, false, true ); } + half4 frag( v2f v ) : SV_Target { return frag_cutout( v, false ); } + ENDCG + } + } + FallBack Off +} diff --git a/Assets/Cinematic Effects/MotionBlur/Resources/SkinnedVectors.shader.meta b/Assets/Cinematic Effects/MotionBlur/Resources/SkinnedVectors.shader.meta new file mode 100644 index 0000000..e786a23 --- /dev/null +++ b/Assets/Cinematic Effects/MotionBlur/Resources/SkinnedVectors.shader.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: ed3e87d88a83040418d4b34782b7b422 +ShaderImporter: + defaultTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/MotionBlur/Resources/SolidVectors.shader b/Assets/Cinematic Effects/MotionBlur/Resources/SolidVectors.shader new file mode 100644 index 0000000..3c3177d --- /dev/null +++ b/Assets/Cinematic Effects/MotionBlur/Resources/SolidVectors.shader @@ -0,0 +1,127 @@ +// Amplify Motion - Full-scene Motion Blur for Unity Pro +// Copyright (c) Amplify Creations, Lda + +Shader "Hidden/Amplify Motion/SolidVectors" { + Properties { + _MainTex ("Base (RGB)", 2D) = "white" {} + _Cutoff ("Alpha cutoff", Range(0,1)) = 0.25 + } + CGINCLUDE + #pragma fragmentoption ARB_precision_hint_fastest + #include "Shared.cginc" + + struct appdata_t + { + float4 vertex : POSITION; + float2 texcoord : TEXCOORD0; + }; + + struct v2f + { + float4 pos : SV_POSITION; + float4 pos_prev : TEXCOORD0; + float4 pos_curr : TEXCOORD1; + float4 motion : TEXCOORD2; + float4 screen_pos : TEXCOORD3; + float2 uv : TEXCOORD4; + }; + + sampler2D _MainTex; + float4 _MainTex_ST; + float _Cutoff; + + v2f vert_base( appdata_t v, bool mobile ) + { + v2f o; + UNITY_INITIALIZE_OUTPUT( v2f, o ); + + float4 pos = o.pos = mul( UNITY_MATRIX_MVP, v.vertex ); + float4 pos_prev = mul( _AM_MATRIX_PREV_MVP, v.vertex ); + float4 pos_curr = o.pos; + + #if UNITY_UV_STARTS_AT_TOP + pos_curr.y = -pos_curr.y; + pos_prev.y = -pos_prev.y; + if ( _ProjectionParams.x > 0 ) + pos.y = -pos.y; + #endif + + if ( mobile ) + o.motion = SolidMotionVector( pos_prev, pos_curr, _AM_OBJECT_ID ); + else + { + o.pos_prev = pos_prev; + o.pos_curr = pos_curr; + } + + o.screen_pos = ComputeScreenPos( pos ); + o.uv = TRANSFORM_TEX( v.texcoord, _MainTex ); + return o; + } + + inline half4 frag_opaque( v2f i, const bool mobile ) + { + if ( !DepthTest( i.screen_pos ) ) + discard; + + if ( mobile ) + return i.motion; + else + return SolidMotionVector( i.pos_prev, i.pos_curr, _AM_OBJECT_ID ); + } + + inline half4 frag_cutout( v2f i, const bool mobile ) + { + if ( !DepthTest( i.screen_pos ) || tex2D( _MainTex, i.uv ).a < _Cutoff ) + discard; + + if ( mobile ) + return i.motion; + else + return SolidMotionVector( i.pos_prev, i.pos_curr, _AM_OBJECT_ID ); + } + ENDCG + SubShader { + Tags { "RenderType"="Opaque" } + Blend Off Cull Off Fog { Mode off } + ZTest LEqual ZWrite On + Pass { + Name "MOB_OPAQUE" + CGPROGRAM + #pragma vertex vert + #pragma fragment frag + v2f vert( appdata_t v ) { return vert_base( v, true ); } + half4 frag( v2f v ) : SV_Target { return frag_opaque( v, true ); } + ENDCG + } + Pass { + Name "MOB_CUTOUT" + CGPROGRAM + #pragma vertex vert + #pragma fragment frag + v2f vert( appdata_t v ) { return vert_base( v, true ); } + half4 frag( v2f v ) : SV_Target { return frag_cutout( v, true ); } + ENDCG + } + Pass { + Name "STD_OPAQUE" + CGPROGRAM + #pragma vertex vert + #pragma fragment frag + v2f vert( appdata_t v ) { return vert_base( v, false ); } + half4 frag( v2f v ) : SV_Target { return frag_opaque( v, false ); } + ENDCG + } + Pass { + Name "STD_CUTOUT" + CGPROGRAM + #pragma vertex vert + #pragma fragment frag + v2f vert( appdata_t v ) { return vert_base( v, false ); } + half4 frag( v2f v ) : SV_Target { return frag_cutout( v, false ); } + ENDCG + } + } + + FallBack Off +} diff --git a/Assets/Cinematic Effects/MotionBlur/Resources/SolidVectors.shader.meta b/Assets/Cinematic Effects/MotionBlur/Resources/SolidVectors.shader.meta new file mode 100644 index 0000000..63712bf --- /dev/null +++ b/Assets/Cinematic Effects/MotionBlur/Resources/SolidVectors.shader.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: a9c02c5d9708d884c87086d5f4f8765a +ShaderImporter: + defaultTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/ScreenSpaceReflection.meta b/Assets/Cinematic Effects/ScreenSpaceReflection.meta new file mode 100644 index 0000000..914d7cb --- /dev/null +++ b/Assets/Cinematic Effects/ScreenSpaceReflection.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 0190f05cacbdca84c932a2f2e0035c51 +folderAsset: yes +timeCreated: 1448358989 +licenseType: Pro +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/ScreenSpaceReflection/Editor.meta b/Assets/Cinematic Effects/ScreenSpaceReflection/Editor.meta new file mode 100644 index 0000000..6368712 --- /dev/null +++ b/Assets/Cinematic Effects/ScreenSpaceReflection/Editor.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 4834a3e1213004b48b14703e6723c17c +folderAsset: yes +timeCreated: 1448359076 +licenseType: Pro +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/ScreenSpaceReflection/Editor/ScreenSpaceReflectionEditor.cs b/Assets/Cinematic Effects/ScreenSpaceReflection/Editor/ScreenSpaceReflectionEditor.cs new file mode 100644 index 0000000..ccab011 --- /dev/null +++ b/Assets/Cinematic Effects/ScreenSpaceReflection/Editor/ScreenSpaceReflectionEditor.cs @@ -0,0 +1,156 @@ +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 + { + private enum SettingsMode + { + HighQuality, + Default, + Performance, + Custom, + } + + [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(); + + var currentState = ((ScreenSpaceReflection)target).settings; + + var settingsMode = SettingsMode.Custom; + if (currentState.Equals(ScreenSpaceReflection.SSRSettings.performanceSettings)) + settingsMode = SettingsMode.Performance; + else if (currentState.Equals(ScreenSpaceReflection.SSRSettings.defaultSettings)) + settingsMode = SettingsMode.Default; + else if (currentState.Equals(ScreenSpaceReflection.SSRSettings.highQualitySettings)) + settingsMode = SettingsMode.HighQuality; + + EditorGUI.BeginChangeCheck(); + settingsMode = (SettingsMode)EditorGUILayout.EnumPopup("Preset", settingsMode); + if (EditorGUI.EndChangeCheck()) + Apply(settingsMode); + + // move into the m_Settings fields... + foreach (var property in m_Properties) + EditorGUILayout.PropertyField(property); + + serializedObject.ApplyModifiedProperties(); + } + + private void Apply(SettingsMode settingsMode) + { + switch (settingsMode) + { + case SettingsMode.Default: + Apply(ScreenSpaceReflection.SSRSettings.defaultSettings); + break; + case SettingsMode.HighQuality: + Apply(ScreenSpaceReflection.SSRSettings.highQualitySettings); + break; + case SettingsMode.Performance: + Apply(ScreenSpaceReflection.SSRSettings.performanceSettings); + break; + } + } + + 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/Assets/Cinematic Effects/ScreenSpaceReflection/Editor/ScreenSpaceReflectionEditor.cs.meta b/Assets/Cinematic Effects/ScreenSpaceReflection/Editor/ScreenSpaceReflectionEditor.cs.meta new file mode 100644 index 0000000..50e7bbc --- /dev/null +++ b/Assets/Cinematic Effects/ScreenSpaceReflection/Editor/ScreenSpaceReflectionEditor.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: eb0236f80884a1f4793c96b4d2da5c68 +timeCreated: 1446039760 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/ScreenSpaceReflection/Resources.meta b/Assets/Cinematic Effects/ScreenSpaceReflection/Resources.meta new file mode 100644 index 0000000..c1d5872 --- /dev/null +++ b/Assets/Cinematic Effects/ScreenSpaceReflection/Resources.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: a19e50b158b32e6458d43c13406863ff +folderAsset: yes +timeCreated: 1453972687 +licenseType: Pro +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/ScreenSpaceReflection/Resources/ScreenSpaceRaytrace.cginc b/Assets/Cinematic Effects/ScreenSpaceReflection/Resources/ScreenSpaceRaytrace.cginc new file mode 100644 index 0000000..34b34ce --- /dev/null +++ b/Assets/Cinematic Effects/ScreenSpaceReflection/Resources/ScreenSpaceRaytrace.cginc @@ -0,0 +1,265 @@ +/** +\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 refine, + 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; + if (refine && intersecting && stepRate > 1) { + + + // We're going back a step. + P -= dP, Q.z -= dQ.z, k -= dk; + prevZMaxEstimate = Q.z / k; + rayZMin = prevZMaxEstimate; + rayZMax = prevZMaxEstimate; + + intersecting = false; + int refinementStepCount = 0; + int refinementMaxSteps = stepRate; + + float refinementConstant = 1.0 / stepRate; + dQ.z *= refinementConstant; + dP *= refinementConstant; + dk *= refinementConstant; + + // Refinement + rayIterations(traceBehindObjects, P, stepDirection, end, refinementStepCount, refinementMaxSteps, intersecting, + sceneZ, dP, Q, dQ, k, dk, + rayZMin, rayZMax, prevZMaxEstimate, permute, hitPixel, + invSize, layerThickness); + stepCount += refinementStepCount * refinementConstant - 1.0; + //stepCount = refinementStepCount; + intersecting = true; + } + + + // 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/Assets/Cinematic Effects/ScreenSpaceReflection/Resources/ScreenSpaceRaytrace.cginc.meta b/Assets/Cinematic Effects/ScreenSpaceReflection/Resources/ScreenSpaceRaytrace.cginc.meta new file mode 100644 index 0000000..9b2d477 --- /dev/null +++ b/Assets/Cinematic Effects/ScreenSpaceReflection/Resources/ScreenSpaceRaytrace.cginc.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 6f70a4658ebf5f947abc302c6b49a6ba +timeCreated: 1449750676 +licenseType: Pro +ShaderImporter: + defaultTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/ScreenSpaceReflection/Resources/ScreenSpaceReflection.shader b/Assets/Cinematic Effects/ScreenSpaceReflection/Resources/ScreenSpaceReflection.shader new file mode 100644 index 0000000..7cbe318 --- /dev/null +++ b/Assets/Cinematic Effects/ScreenSpaceReflection/Resources/ScreenSpaceReflection.shader @@ -0,0 +1,1161 @@ +/** +\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; + + + sampler2D _MainTex; + + int _VisualizeWhereBilateral; + int _EnableSSR; + int _DebugMode; + int _HalfResolution; + int _TreatBackfaceHitAsMiss; + int _AllowBackwardsRays; + int _TraceEverywhere; + + + // 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; + float4 _SourceToTempUV; + + int _EnableRefine; + int _AdditiveReflection; + int _ImproveCorners; + + float _ScreenEdgeFading; + + float _MipBias; + + int _UseOcclusion; + + int _MaxSteps; + + int _FullResolutionFiltering; + + int _BilateralUpsampling; + + float _MaxRoughness; + float _RoughnessFalloffRange; + float _SSRMultiplier; + + float _FadeDistance; + + float _DistanceBlur; + + int _TraceBehindObjects; + int _FallbackToSky; + int _UseEdgeDetector; + int _HighlightSuppression; + + /** The height in pixels of a 1m object if viewed from 1m away. */ + float _PixelsPerMeterAtOneMeter; + + int _UseAverageRayDistance; + sampler2D _AverageRayDistanceBuffer; + + // 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 * _SourceToTempUV.zw; + 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); + } + + if ((!_TraceEverywhere) && (smoothness < (1.0 - _MaxRoughness)) ) { + 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, + _EnableRefine == 1, + _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; + } + } + } else if (_FallbackToSky > 0) { + float sceneZ = tex2Dlod(_CameraDepthTexture, float4(tsPResult, 0, 0)).r; + sceneZ = -LinearEyeDepth(sceneZ); + if (sceneZ < -1000) { // 1km ~= infinity + confidence = 1.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 * _SourceToTempUV.xy); + + 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; + + if(_EnableSSR == 0) { + confidence = 0.0; + } + + 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); + } + if (_UseOcclusion) { + finalGlossyTerm *= occlusion; + } + + if (_DebugMode == 1) + return float4(incomingRadiance,0); + if (_DebugMode == 2) + return float4(ssrResult,0); + if (_DebugMode == 3) + return float4(finalGlossyTerm,0); + if (_DebugMode == 4) + return confidence; + if (_DebugMode == 5) + return roughness; + if (_DebugMode == 6) + return float4(baseColor,0); + if (_DebugMode == 7) + return float4(specColor,0); + if (_DebugMode == 8) + return 1.0-oneMinusReflectivity; + if (_DebugMode == 9) + return float4(specEmission.rgb,0); + if (_DebugMode == 10) + return float4(specEmission.rgb-ssrResult,0); + if (_DebugMode == 11) + return float4(ssrResult-specEmission.rgb,0); + if (_DebugMode == 12) + return gbuffer3; + if (_DebugMode == 13) + return -float4(gbuffer3.rgb, 0.0); + if (_DebugMode == 14) // Mip level, stored directly in ssrResult + return float4(incomingRadiance, 0); + + // 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; + if (_FullResolutionFiltering) { + for (int i = -2*radius; i <= 2*radius; ++i) { + float4 temp; + float tapRoughness = midpointRoughness; + float3 tapNormal = midpointNormal; + float2 tsTap = tsP + (_Axis.xy * _MainTex_TexelSize.xy * float2(i,i)); + + temp = tex2D(_MainTex, tsTap); + + int gaussWeightIndex; + #if defined(UNITY_COMPILER_HLSL) && !defined(SHADER_API_D3D9) + gaussWeightIndex = abs(i) >> 1; // We purposefully do integer division, but that does not compile on hlsl2glsl + #else + gaussWeightIndex = frac(abs(i) / 2); + #endif + + float weight = temp.a * gaussWeights[gaussWeightIndex]*0.5; + // Bilateral filtering + if (_ImproveCorners) { + nAndRough = tex2D(_NormalAndRoughnessTexture, tsTap); + tapRoughness = nAndRough.a; + tapNormal = nAndRough.rgb * 2 - 1; + weight *= normalWeight(midpointNormal, tapNormal); + } + weightSum += weight; + resultSum += temp*weight; + unweightedResultSum += temp; + } + } else { + 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); + + 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; + + 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 * _SourceToTempUV.zw).a; + + float rayDistance = 0.0; + if (_UseAverageRayDistance) { + rayDistance = tex2D(_AverageRayDistanceBuffer, tsP).r; + } else { + 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 = lerp(nonPhysicalMip, mip, _DistanceBlur); + mip = max(0, min(4, mip + _MipBias)); + + if (_DebugMode == 14) { + return float4(ansiGradient(mip*0.25), 1.0); + } + + float4 result; + { + int mipMin = int(mip); + int mipMax = min(mipMin + 1, 4); + float mipLerp = mip-mipMin; + + if (_BilateralUpsampling == 1) { + if (_UseEdgeDetector == 1) { + float nonEdginess = lerp(getEdgeValue(tsP, mipMin), + getEdgeValue(tsP, mipMax), mipLerp); + if (nonEdginess < 0.9) { + result = lerp(bilateralUpsampleReflection(tsP, mipMin), bilateralUpsampleReflection(tsP, mipMax), mipLerp); + if (_VisualizeWhereBilateral == 1) { + result = float4(1, 0, 0, 0); + } + } else { + result = lerp(bilinearUpsampleReflection(tsP, mipMin), bilinearUpsampleReflection(tsP, mipMax), mipLerp); + } + } else { + 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; + + + float alphaModifier = 1.0 - clamp((roughness - (_MaxRoughness - _RoughnessFalloffRange)) / _RoughnessFalloffRange, 0.0, 1.0); + result.a *= alphaModifier; + return result; + } + + float4 fragBlit(v2f i) : SV_Target + { + // Pixel being shaded + float2 ssP = i.uv2.xy; + return tex2D(_MainTex, ssP); + + } + + float edgeDetector(float2 tsP, float2 axis, float2 texelSize) { + float4 temp = tex2D(_NormalAndRoughnessTexture, tsP); + float midpointRoughness = temp.a; + float3 midpointNormal = temp.rgb * 2 - 1; + + float tapRoughness; + float3 tapNormal; + float2 tsTap = tsP + (axis * _MainTex_TexelSize.xy); + + temp = tex2D(_NormalAndRoughnessTexture, tsTap); + tapRoughness = temp.a; + tapNormal = temp.rgb * 2 - 1; + + float weight = 1.0; + weight *= roughnessWeight(midpointRoughness, tapRoughness); + weight *= normalWeight(midpointNormal, tapNormal); + + return weight; + } + + + float4 fragEdge(v2f i) : SV_Target + { + float2 tsP = i.uv2.xy; + return edgeDetector(tsP, float2(1,0), _MainTex_TexelSize.xy) * edgeDetector(tsP, float2(0,1), _MainTex_TexelSize.xy); + } + + int _LastMip; + float4 fragMin(v2f i) : SV_Target + { + float2 tsP = i.uv2.xy; + float2 lastTexSize = mipToSize(_LastMip); + float2 lastTexSizeInv = 1.0 / lastTexSize;//_SourceToTempUV.xy * exp2(mip); + 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); + } + + + float3 csPositionToOldNormalizedScreenCoordinate(float3 csPosition) + { + // We could multiply these matrices together on the CPU + float4 oldCSPosition = mul(_CurrentCameraToPreviousCamera, float4(csPosition, 1.0)); + float4 oldSSCoordinate = mul(_ProjectToPixelMatrix, oldCSPosition); + return float3((oldSSCoordinate.xy / oldSSCoordinate.w) * _InvScreenSize, oldCSPosition.z); + } + + float4 fragTemporalFilter(v2f i) : SV_Target + { + float2 tsP = i.uv2.xy; + float depth = SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, tsP); + float3 csPosition = GetPosition(tsP); + + float rayDistance = 0.0; + if (_UseAverageRayDistance) { + rayDistance = tex2D(_AverageRayDistanceBuffer, tsP).r; + } else { + rayDistance = tex2D(_HitPointTexture, tsP).b; + } + + // Virtual is the physics sense, not the other 20+ interpretations in CG + float3 virtualReflectionCSPosition = normalize(csPosition) * rayDistance + csPosition; + + float3 oldTSP = csPositionToOldNormalizedScreenCoordinate(csPosition); + float3 oldVirtualReflectionTSP = csPositionToOldNormalizedScreenCoordinate(virtualReflectionCSPosition); + + float oldCSZ = tex2D(_PreviousCSZBuffer, oldTSP.xy); + float4 currentResult = tex2D(_FinalReflectionTexture, tsP); + float4 oldResult = tex2D(_PreviousReflectionTexture, oldVirtualReflectionTSP.xy); + + float zError = abs(oldCSZ - oldTSP.z); + // Start knocking down contribution at 5cm error, go to 0 at 5 more cm later + float fallbackStart = 0.05; + float fallbackEnd = 0.05; + float zAlphaModifier = 1.0 - clamp((zError - fallbackStart) * (1.0 / fallbackEnd), 0.0, 1.0); + + float alpha = _TemporalAlpha; + alpha *= zAlphaModifier; + + if (_UseTemporalConfidence) { + alpha *= oldResult.w; + } + + // Always compress + currentResult.rgb = highlightCompression(currentResult.rgb); + oldResult.rgb = highlightCompression(oldResult.rgb); + + float4 resultValue = lerp(currentResult, oldResult, alpha); + + resultValue.rgb = highlightDecompression(resultValue.rgb); + + + return resultValue; + + } + + + float4 fragAverageRayDistance(v2f i) : SV_Target + { + float2 tsP = i.uv2.xy; + + float sumRayDistance = tex2D(_HitPointTexture, tsP).b; + float sumWeight = 1.0; + + float roughness = 1.0 - tex2D(_CameraGBufferTexture1, tsP).a; + float step = roughness * 3.0; + /* + for (float x = -step; x < step; x += 2 * step) { + for (float y = -step; y < step; y += 2 * step) { + float weight = 0.5; + sumRayDistance += weight * tex2D(_HitPointTexture, (float2(x,y) * _InvScreenSize) + tsP).b; + sumWeight += weight; + } + } + */ + return float4(sumRayDistance / sumWeight, 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 * 2.0; + for (int i = 0; i < NUM_POISSON_TAPS; i++) { + float2 p = tsP + poissonSamples[i] * sampleRadius; + float4 tap = tex2Dlod(_MainTex, float4(p, 0, 0)); + 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, step size 1 + 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, 1); } + ENDCG + } + + // 1: Raytrace, step size 2 + Pass { + CGPROGRAM + #pragma exclude_renderers gles xbox360 ps3 + #pragma vertex vert + #pragma fragment fragRaytrace2 + #pragma target 3.0 + float4 fragRaytrace2(v2f i) : SV_Target { return fragRaytrace(i, 2); } + ENDCG + } + + // 2: Raytrace, step size 4 + Pass { + CGPROGRAM + #pragma exclude_renderers gles xbox360 ps3 + #pragma vertex vert + #pragma fragment fragRaytrace4 + #pragma target 3.0 + float4 fragRaytrace4(v2f i) : SV_Target { return fragRaytrace(i, 4); } + ENDCG + } + + // 3: Raytrace, step size 8 + Pass { + CGPROGRAM + #pragma exclude_renderers gles xbox360 ps3 + #pragma vertex vert + #pragma fragment fragRaytrace8 + #pragma target 3.0 + float4 fragRaytrace8(v2f i) : SV_Target { return fragRaytrace(i, 8); } + ENDCG + } + + // 4: Raytrace, step size 16 + Pass { + CGPROGRAM + #pragma exclude_renderers gles xbox360 ps3 + #pragma vertex vert + #pragma fragment fragRaytrace16 + #pragma target 3.0 + float4 fragRaytrace16(v2f i) : SV_Target { return fragRaytrace(i, 16); } + ENDCG + } + + // 5: Composite + Pass { + CGPROGRAM + #pragma exclude_renderers gles xbox360 ps3 + #pragma vertex vert + #pragma fragment fragComposite + #pragma target 3.0 + ENDCG + } + + // 6: GBlur + Pass { + CGPROGRAM + #pragma exclude_renderers gles xbox360 ps3 + #pragma vertex vert + #pragma fragment fragGBlur + #pragma target 3.0 + ENDCG + } + + // 7: CompositeSSR + Pass { + CGPROGRAM + #pragma exclude_renderers gles xbox360 ps3 + #pragma vertex vert + #pragma fragment fragCompositeSSR + #pragma target 3.0 + ENDCG + } + + // 8: Simple Blit + Pass { + CGPROGRAM + #pragma exclude_renderers gles xbox360 ps3 + #pragma vertex vert + #pragma fragment fragBlit + #pragma target 3.0 + ENDCG + } + + // 9: Generate Edge Texture + Pass { + CGPROGRAM + #pragma exclude_renderers gles xbox360 ps3 + #pragma vertex vert + #pragma fragment fragEdge + #pragma target 3.0 + ENDCG + } + + // 10: Min mip generation + Pass { + CGPROGRAM + #pragma exclude_renderers gles xbox360 ps3 + #pragma vertex vert + #pragma fragment fragMin + #pragma target 3.0 + ENDCG + } + + // 11: 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 + } + + // 12: 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 + } + + // 13: 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 + } + + // 14: Temporally filter buffer + Pass{ + CGPROGRAM + #pragma exclude_renderers gles xbox360 ps3 + #pragma vertex vert + #pragma fragment fragTemporalFilter + #pragma target 3.0 + ENDCG + } + + // 15: Generate average ray distance + Pass{ + CGPROGRAM + #pragma exclude_renderers gles xbox360 ps3 + #pragma vertex vert + #pragma fragment fragAverageRayDistance + #pragma target 3.0 + ENDCG + } + + // 16: 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 off + +} diff --git a/Assets/Cinematic Effects/ScreenSpaceReflection/Resources/ScreenSpaceReflection.shader.meta b/Assets/Cinematic Effects/ScreenSpaceReflection/Resources/ScreenSpaceReflection.shader.meta new file mode 100644 index 0000000..f6718fe --- /dev/null +++ b/Assets/Cinematic Effects/ScreenSpaceReflection/Resources/ScreenSpaceReflection.shader.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 7e2fcc83af19e744787647ec0ac5d42c +timeCreated: 1449750821 +licenseType: Pro +ShaderImporter: + defaultTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/ScreenSpaceReflection/ScreenSpaceReflection.cs b/Assets/Cinematic Effects/ScreenSpaceReflection/ScreenSpaceReflection.cs new file mode 100644 index 0000000..7cecf5e --- /dev/null +++ b/Assets/Cinematic Effects/ScreenSpaceReflection/ScreenSpaceReflection.cs @@ -0,0 +1,716 @@ +using System; +using UnityEngine; + +namespace UnityStandardAssets.CinematicEffects +{ + [ExecuteInEditMode] + [RequireComponent(typeof(Camera))] + [AddComponentMenu("Image Effects/Rendering/Screen Space Reflection")] +#if UNITY_5_4_OR_NEWER + [ImageEffectAllowedInSceneView] +#endif + public class ScreenSpaceReflection : MonoBehaviour + { + public enum SSRDebugMode + { + None = 0, + IncomingRadiance = 1, + SSRResult = 2, + FinalGlossyTerm = 3, + SSRMask = 4, + Roughness = 5, + BaseColor = 6, + SpecColor = 7, + Reflectivity = 8, + ReflectionProbeOnly = 9, + ReflectionProbeMinusSSR = 10, + SSRMinusReflectionProbe = 11, + NoGlossy = 12, + NegativeNoGlossy = 13, + MipLevel = 14, + } + + public enum SSRResolution + { + FullResolution = 0, + HalfTraceFullResolve = 1, + HalfResolution = 2, + } + + [Serializable] + public struct SSRSettings + { + [AttributeUsage(AttributeTargets.Field)] + public class LayoutAttribute : PropertyAttribute + {} + + [Layout] + public BasicSettings basicSettings; + + [Layout] + public ReflectionSettings reflectionSettings; + + [Layout] + public AdvancedSettings advancedSettings; + + [Layout] + public DebugSettings debugSettings; + + private static readonly SSRSettings s_Performance = new SSRSettings + { + basicSettings = new BasicSettings + { + screenEdgeFading = 0, + maxDistance = 10.0f, + fadeDistance = 10.0f, + reflectionMultiplier = 1.0f, + enableHDR = false, + additiveReflection = false + }, + reflectionSettings = new ReflectionSettings + { + maxSteps = 64, + rayStepSize = 4, + widthModifier = 0.5f, + smoothFallbackThreshold = 0.4f, + distanceBlur = 1.0f, + fresnelFade = 0.2f, + fresnelFadePower = 2.0f, + smoothFallbackDistance = 0.05f, + }, + advancedSettings = new AdvancedSettings + { + useTemporalConfidence = false, + temporalFilterStrength = 0.0f, + treatBackfaceHitAsMiss = false, + allowBackwardsRays = false, + traceBehindObjects = true, + highQualitySharpReflections = false, + traceEverywhere = false, + resolution = SSRResolution.HalfResolution, + bilateralUpsample = false, + improveCorners = false, + reduceBanding = false, + highlightSuppression = false + }, + debugSettings = new DebugSettings + { + debugMode = SSRDebugMode.None + } + }; + + private static readonly SSRSettings s_Default = new SSRSettings + { + basicSettings = new BasicSettings + { + screenEdgeFading = 0.03f, + maxDistance = 100.0f, + fadeDistance = 100.0f, + reflectionMultiplier = 1.0f, + enableHDR = true, + additiveReflection = false, + }, + reflectionSettings = new ReflectionSettings + { + maxSteps = 128, + rayStepSize = 3, + widthModifier = 0.5f, + smoothFallbackThreshold = 0.2f, + distanceBlur = 1.0f, + fresnelFade = 0.2f, + fresnelFadePower = 2.0f, + smoothFallbackDistance = 0.05f, + }, + advancedSettings = new AdvancedSettings + { + useTemporalConfidence = true, + temporalFilterStrength = 0.7f, + treatBackfaceHitAsMiss = false, + allowBackwardsRays = false, + traceBehindObjects = true, + highQualitySharpReflections = true, + traceEverywhere = true, + resolution = SSRResolution.HalfTraceFullResolve, + bilateralUpsample = true, + improveCorners = true, + reduceBanding = true, + highlightSuppression = false + }, + debugSettings = new DebugSettings + { + debugMode = SSRDebugMode.None + } + }; + + private static readonly SSRSettings s_HighQuality = new SSRSettings + { + basicSettings = new BasicSettings + { + screenEdgeFading = 0.03f, + maxDistance = 100.0f, + fadeDistance = 100.0f, + reflectionMultiplier = 1.0f, + enableHDR = true, + additiveReflection = false, + }, + reflectionSettings = new ReflectionSettings + { + maxSteps = 512, + rayStepSize = 1, + widthModifier = 0.5f, + smoothFallbackThreshold = 0.2f, + distanceBlur = 1.0f, + fresnelFade = 0.2f, + fresnelFadePower = 2.0f, + smoothFallbackDistance = 0.05f, + }, + advancedSettings = new AdvancedSettings + { + useTemporalConfidence = true, + temporalFilterStrength = 0.7f, + treatBackfaceHitAsMiss = false, + allowBackwardsRays = false, + traceBehindObjects = true, + highQualitySharpReflections = true, + traceEverywhere = true, + resolution = SSRResolution.HalfTraceFullResolve, + bilateralUpsample = true, + improveCorners = true, + reduceBanding = true, + highlightSuppression = false + }, + debugSettings = new DebugSettings + { + debugMode = SSRDebugMode.None + } + }; + + + public static SSRSettings performanceSettings + { + get { return s_Performance; } + } + + public static SSRSettings defaultSettings + { + get { return s_Default; } + } + + public static SSRSettings highQualitySettings + { + get { return s_HighQuality; } + } + } + + [Serializable] + public struct BasicSettings + { + /// BASIC SETTINGS + [Tooltip("Nonphysical multiplier for the SSR reflections. 1.0 is physically based.")] + [Range(0.0f, 2.0f)] + public float reflectionMultiplier; + + [Tooltip("Maximum reflection distance in world units.")] + [Range(0.5f, 1000.0f)] + public float maxDistance; + + [Tooltip("How far away from the maxDistance to begin fading SSR.")] + [Range(0.0f, 1000.0f)] + public float fadeDistance; + + [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 screenEdgeFading; + + [Tooltip("Enable for better reflections of very bright objects at a performance cost")] + public bool enableHDR; + + // 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("Add reflections on top of existing ones. Not physically correct.")] + public bool additiveReflection; + } + + [Serializable] + public struct ReflectionSettings + { + /// REFLECTIONS + [Tooltip("Max raytracing length.")] + [Range(16, 2048)] + public int maxSteps; + + [Tooltip("Log base 2 of ray tracing coarse step size. Higher traces farther, lower gives better quality silhouettes.")] + [Range(0, 4)] + public int rayStepSize; + + [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("Increase if reflections flicker on very rough surfaces.")] + [Range(0.0f, 1.0f)] + public float smoothFallbackThreshold; + + [Tooltip("Start falling back to non-SSR value solution at smoothFallbackThreshold - smoothFallbackDistance, with full fallback occuring at smoothFallbackThreshold.")] + [Range(0.0f, 0.2f)] + public float smoothFallbackDistance; + + [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; + + [Tooltip("Controls how blurry reflections get as objects are further from the camera. 0 is constant blur no matter trace distance or distance from camera. 1 fully takes into account both factors.")] + [Range(0.0f, 1.0f)] + public float distanceBlur; + } + + [Serializable] + public struct AdvancedSettings + { + /// ADVANCED + [Range(0.0f, 0.99f)] + [Tooltip("Increase to decrease flicker in scenes; decrease to prevent ghosting (especially in dynamic scenes). 0 gives maximum performance.")] + public float temporalFilterStrength; + + [Tooltip("Enable to limit ghosting from applying the temporal filter.")] + public bool useTemporalConfidence; + + [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.")] + public bool traceBehindObjects; + + [Tooltip("Enable to increase quality of the sharpest reflections (through filtering), at a performance cost.")] + public bool highQualitySharpReflections; + + [Tooltip("Improves quality in scenes with varying smoothness, at a potential performance cost.")] + public bool traceEverywhere; + + [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.")] + public bool treatBackfaceHitAsMiss; + + [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 allowBackwardsRays; + + [Tooltip("Improve visual fidelity of reflections on rough surfaces near corners in the scene, at the cost of a small amount of performance.")] + public bool improveCorners; + + [Tooltip("Half resolution SSRR is much faster, but less accurate. Quality can be reclaimed for some performance by doing the resolve at full resolution.")] + public SSRResolution resolution; + + [Tooltip("Drastically improves reflection reconstruction quality at the expense of some performance.")] + public bool bilateralUpsample; + + [Tooltip("Improve visual fidelity of mirror reflections at the cost of a small amount of performance.")] + public bool reduceBanding; + + [Tooltip("Enable to limit the effect a few bright pixels can have on rougher surfaces")] + public bool highlightSuppression; + } + + [Serializable] + public struct DebugSettings + { + /// DEBUG + [Tooltip("Various Debug Visualizations")] + public SSRDebugMode debugMode; + } + + + [SerializeField] + public SSRSettings settings = SSRSettings.defaultSettings; + + ///////////// Unexposed Variables ////////////////// + + // Perf optimization we still need to test across platforms + [Tooltip("Enable to try and bypass expensive bilateral upsampling away from edges. There is a slight performance hit for generating the edge buffers, but a potentially high performance savings from bypassing bilateral upsampling where it is unneeded. Test on your target platforms to see if performance improves.")] + private bool useEdgeDetector = false; + + // Debug variable, useful for forcing all surfaces in a scene to reflection with arbitrary sharpness/roughness + [Range(-4.0f, 4.0f)] + private float mipBias = 0.0f; + + // Flag for whether to knock down the reflection term by occlusion stored in the gbuffer. Currently consistently gives + // better results when true, so this flag is private for now. + private bool useOcclusion = true; + + // When enabled, all filtering is performed at the highest resolution. This is extraordinarily slow, and should only be used during development. + private bool fullResolutionFiltering = false; + + // Crude sky fallback, feature-gated until next revision + private bool fallbackToSky = false; + + // For next release; will improve quality at the expense of performance + private bool computeAverageRayDistance = false; + + // Internal values for temporal filtering + private bool m_HasInformationFromPreviousFrame; + private Matrix4x4 m_PreviousWorldToCameraMatrix; + private RenderTexture m_PreviousDepthBuffer; + private RenderTexture m_PreviousHitBuffer; + private RenderTexture m_PreviousReflectionBuffer; + + [NonSerialized] + private RenderTextureUtility m_RTU = new RenderTextureUtility(); + + [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; + } + } + + // Shader pass indices used by the effect + private enum PassIndex + { + RayTraceStep1 = 0, + RayTraceStep2 = 1, + RayTraceStep4 = 2, + RayTraceStep8 = 3, + RayTraceStep16 = 4, + CompositeFinal = 5, + Blur = 6, + CompositeSSR = 7, + Blit = 8, + EdgeGeneration = 9, + MinMipGeneration = 10, + HitPointToReflections = 11, + BilateralKeyPack = 12, + BlitDepthAsCSZ = 13, + TemporalFilter = 14, + AverageRayDistanceGeneration = 15, + PoissonBlur = 16, + } + + + private void OnEnable() + { + if (!ImageEffectHelper.IsSupported(shader, false, true, this)) + { + enabled = false; + return; + } + + GetComponent().depthTextureMode |= DepthTextureMode.Depth; + } + + void OnDisable() + { + if (m_Material) + DestroyImmediate(m_Material); + if (m_PreviousDepthBuffer) + DestroyImmediate(m_PreviousDepthBuffer); + if (m_PreviousHitBuffer) + DestroyImmediate(m_PreviousHitBuffer); + if (m_PreviousReflectionBuffer) + DestroyImmediate(m_PreviousReflectionBuffer); + + m_Material = null; + m_PreviousDepthBuffer = null; + m_PreviousHitBuffer = null; + m_PreviousReflectionBuffer = null; + } + + private void PreparePreviousBuffers(int w, int h) + { + if (m_PreviousDepthBuffer != null) + { + if ((m_PreviousDepthBuffer.width != w) || (m_PreviousDepthBuffer.height != h)) + { + DestroyImmediate(m_PreviousDepthBuffer); + DestroyImmediate(m_PreviousHitBuffer); + DestroyImmediate(m_PreviousReflectionBuffer); + m_PreviousDepthBuffer = null; + m_PreviousHitBuffer = null; + m_PreviousReflectionBuffer = null; + } + } + if (m_PreviousDepthBuffer == null) + { + m_PreviousDepthBuffer = new RenderTexture(w, h, 0, RenderTextureFormat.RFloat); + m_PreviousHitBuffer = new RenderTexture(w, h, 0, RenderTextureFormat.ARGBHalf); + m_PreviousReflectionBuffer = new RenderTexture(w, h, 0, RenderTextureFormat.ARGBHalf); + } + } + + [ImageEffectOpaque] + public void OnRenderImage(RenderTexture source, RenderTexture destination) + { + if (material == null) + { + Graphics.Blit(source, destination); + return; + } + if (m_HasInformationFromPreviousFrame) + { + m_HasInformationFromPreviousFrame = (m_PreviousDepthBuffer != null) && + (source.width == m_PreviousDepthBuffer.width) && + (source.height == m_PreviousDepthBuffer.height); + } + bool doTemporalFilterThisFrame = m_HasInformationFromPreviousFrame && settings.advancedSettings.temporalFilterStrength > 0.0; + m_HasInformationFromPreviousFrame = false; + + // Not using deferred shading? Just blit source to destination. + if (Camera.current.actualRenderingPath != RenderingPath.DeferredShading) + { + Graphics.Blit(source, destination); + return; + } + + var rtW = source.width; + var rtH = source.height; + + // RGB: Normals, A: Roughness. + // Has the nice benefit of allowing us to control the filtering mode as well. + RenderTexture bilateralKeyTexture = m_RTU.GetTemporaryRenderTexture(rtW, rtH, 0, RenderTextureFormat.ARGB32); + bilateralKeyTexture.filterMode = FilterMode.Point; + Graphics.Blit(source, bilateralKeyTexture, material, (int)PassIndex.BilateralKeyPack); + material.SetTexture("_NormalAndRoughnessTexture", bilateralKeyTexture); + + float sWidth = source.width; + float sHeight = source.height; + + Vector2 sourceToTempUV = new Vector2(sWidth / rtW, sHeight / rtH); + + int downsampleAmount = (settings.advancedSettings.resolution == SSRResolution.FullResolution) ? 1 : 2; + + rtW = rtW / downsampleAmount; + rtH = rtH / downsampleAmount; + + material.SetVector("_SourceToTempUV", new Vector4(sourceToTempUV.x, sourceToTempUV.y, 1.0f / sourceToTempUV.x, 1.0f / sourceToTempUV.y)); + + + Matrix4x4 P = GetComponent().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])); + + /** The height in pixels of a 1m object if viewed from 1m away. */ + float pixelsPerMeterAtOneMeter = sWidth / (-2.0f * (float)(Math.Tan(GetComponent().fieldOfView / 180.0 * Math.PI * 0.5))); + material.SetFloat("_PixelsPerMeterAtOneMeter", pixelsPerMeterAtOneMeter); + + + float sx = sWidth / 2.0f; + float sy = sHeight / 2.0f; + + 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.SetVector("_ScreenSize", new Vector2(sWidth, sHeight)); + material.SetVector("_ReflectionBufferSize", new Vector2(rtW, rtH)); + Vector2 invScreenSize = new Vector2((float)(1.0 / sWidth), (float)(1.0 / sHeight)); + + Matrix4x4 worldToCameraMatrix = GetComponent().worldToCameraMatrix; + Matrix4x4 cameraToWorldMatrix = GetComponent().worldToCameraMatrix.inverse; + material.SetVector("_InvScreenSize", invScreenSize); + material.SetVector("_ProjInfo", projInfo); // used for unprojection + material.SetMatrix("_ProjectToPixelMatrix", projectToPixelMatrix); + material.SetMatrix("_WorldToCameraMatrix", worldToCameraMatrix); + material.SetMatrix("_CameraToWorldMatrix", cameraToWorldMatrix); + material.SetInt("_EnableRefine", settings.advancedSettings.reduceBanding ? 1 : 0); + material.SetInt("_AdditiveReflection", settings.basicSettings.additiveReflection ? 1 : 0); + material.SetInt("_ImproveCorners", settings.advancedSettings.improveCorners ? 1 : 0); + material.SetFloat("_ScreenEdgeFading", settings.basicSettings.screenEdgeFading); + material.SetFloat("_MipBias", mipBias); + material.SetInt("_UseOcclusion", useOcclusion ? 1 : 0); + material.SetInt("_BilateralUpsampling", settings.advancedSettings.bilateralUpsample ? 1 : 0); + material.SetInt("_FallbackToSky", fallbackToSky ? 1 : 0); + material.SetInt("_TreatBackfaceHitAsMiss", settings.advancedSettings.treatBackfaceHitAsMiss ? 1 : 0); + material.SetInt("_AllowBackwardsRays", settings.advancedSettings.allowBackwardsRays ? 1 : 0); + material.SetInt("_TraceEverywhere", settings.advancedSettings.traceEverywhere ? 1 : 0); + + float z_f = GetComponent().farClipPlane; + float z_n = GetComponent().nearClipPlane; + + Vector3 cameraClipInfo = (float.IsPositiveInfinity(z_f)) ? + new Vector3(z_n, -1.0f, 1.0f) : + new Vector3(z_n * z_f, z_n - z_f, z_f); + + material.SetVector("_CameraClipInfo", cameraClipInfo); + material.SetFloat("_MaxRayTraceDistance", settings.basicSettings.maxDistance); + material.SetFloat("_FadeDistance", settings.basicSettings.fadeDistance); + material.SetFloat("_LayerThickness", settings.reflectionSettings.widthModifier); + + const int maxMip = 5; + RenderTexture[] reflectionBuffers; + RenderTextureFormat intermediateFormat = settings.basicSettings.enableHDR ? RenderTextureFormat.ARGBHalf : RenderTextureFormat.ARGB32; + + reflectionBuffers = new RenderTexture[maxMip]; + for (int i = 0; i < maxMip; ++i) + { + if (fullResolutionFiltering) + reflectionBuffers[i] = m_RTU.GetTemporaryRenderTexture(rtW, rtH, 0, intermediateFormat); + else + reflectionBuffers[i] = m_RTU.GetTemporaryRenderTexture(rtW >> i, rtH >> i, 0, intermediateFormat); + // We explicitly interpolate during bilateral upsampling. + reflectionBuffers[i].filterMode = settings.advancedSettings.bilateralUpsample ? FilterMode.Point : FilterMode.Bilinear; + } + + material.SetInt("_EnableSSR", 1); + material.SetInt("_DebugMode", (int)settings.debugSettings.debugMode); + + material.SetInt("_TraceBehindObjects", settings.advancedSettings.traceBehindObjects ? 1 : 0); + + material.SetInt("_MaxSteps", settings.reflectionSettings.maxSteps); + + RenderTexture rayHitTexture = m_RTU.GetTemporaryRenderTexture(rtW, rtH); + + // We have 5 passes for different step sizes + int tracePass = Mathf.Clamp(settings.reflectionSettings.rayStepSize, 0, 4); + Graphics.Blit(source, rayHitTexture, material, tracePass); + + material.SetTexture("_HitPointTexture", rayHitTexture); + // Resolve the hitpoints into the mirror reflection buffer + Graphics.Blit(source, reflectionBuffers[0], material, (int)PassIndex.HitPointToReflections); + + material.SetTexture("_ReflectionTexture0", reflectionBuffers[0]); + material.SetInt("_FullResolutionFiltering", fullResolutionFiltering ? 1 : 0); + + material.SetFloat("_MaxRoughness", 1.0f - settings.reflectionSettings.smoothFallbackThreshold); + material.SetFloat("_RoughnessFalloffRange", settings.reflectionSettings.smoothFallbackDistance); + + material.SetFloat("_SSRMultiplier", settings.basicSettings.reflectionMultiplier); + + RenderTexture[] edgeTextures = new RenderTexture[maxMip]; + if (settings.advancedSettings.bilateralUpsample && useEdgeDetector) + { + edgeTextures[0] = m_RTU.GetTemporaryRenderTexture(rtW, rtH); + Graphics.Blit(source, edgeTextures[0], material, (int)PassIndex.EdgeGeneration); + for (int i = 1; i < maxMip; ++i) + { + edgeTextures[i] = m_RTU.GetTemporaryRenderTexture(rtW >> i, rtH >> i); + material.SetInt("_LastMip", i - 1); + Graphics.Blit(edgeTextures[i - 1], edgeTextures[i], material, (int)PassIndex.MinMipGeneration); + } + } + + if (settings.advancedSettings.highQualitySharpReflections) + { + RenderTexture filteredReflections = m_RTU.GetTemporaryRenderTexture(reflectionBuffers[0].width, reflectionBuffers[0].height, 0, reflectionBuffers[0].format); + filteredReflections.filterMode = reflectionBuffers[0].filterMode; + reflectionBuffers[0].filterMode = FilterMode.Bilinear; + Graphics.Blit(reflectionBuffers[0], filteredReflections, material, (int)PassIndex.PoissonBlur); + + // Replace the unfiltered buffer with the newly filtered one. + m_RTU.ReleaseTemporaryRenderTexture(reflectionBuffers[0]); + reflectionBuffers[0] = filteredReflections; + material.SetTexture("_ReflectionTexture0", reflectionBuffers[0]); + } + + // Generate the blurred low-resolution buffers + for (int i = 1; i < maxMip; ++i) + { + RenderTexture inputTex = reflectionBuffers[i - 1]; + + RenderTexture hBlur; + if (fullResolutionFiltering) + hBlur = m_RTU.GetTemporaryRenderTexture(rtW, rtH, 0, intermediateFormat); + else + { + int lowMip = i; + hBlur = m_RTU.GetTemporaryRenderTexture(rtW >> lowMip, rtH >> (i - 1), 0, intermediateFormat); + } + for (int j = 0; j < (fullResolutionFiltering ? (i * i) : 1); ++j) + { + // Currently we blur at the resolution of the previous mip level, we could save bandwidth by blurring directly to the lower resolution. + material.SetVector("_Axis", new Vector4(1.0f, 0.0f, 0.0f, 0.0f)); + material.SetFloat("_CurrentMipLevel", i - 1.0f); + + Graphics.Blit(inputTex, hBlur, material, (int)PassIndex.Blur); + + material.SetVector("_Axis", new Vector4(0.0f, 1.0f, 0.0f, 0.0f)); + + inputTex = reflectionBuffers[i]; + Graphics.Blit(hBlur, inputTex, material, (int)PassIndex.Blur); + } + + material.SetTexture("_ReflectionTexture" + i, reflectionBuffers[i]); + + m_RTU.ReleaseTemporaryRenderTexture(hBlur); + } + + + if (settings.advancedSettings.bilateralUpsample && useEdgeDetector) + { + for (int i = 0; i < maxMip; ++i) + material.SetTexture("_EdgeTexture" + i, edgeTextures[i]); + } + material.SetInt("_UseEdgeDetector", useEdgeDetector ? 1 : 0); + + RenderTexture averageRayDistanceBuffer = m_RTU.GetTemporaryRenderTexture(source.width, source.height, 0, RenderTextureFormat.RHalf); + if (computeAverageRayDistance) + { + Graphics.Blit(source, averageRayDistanceBuffer, material, (int)PassIndex.AverageRayDistanceGeneration); + } + material.SetInt("_UseAverageRayDistance", computeAverageRayDistance ? 1 : 0); + material.SetTexture("_AverageRayDistanceBuffer", averageRayDistanceBuffer); + bool resolveDiffersFromTraceRes = (settings.advancedSettings.resolution == SSRResolution.HalfTraceFullResolve); + RenderTexture finalReflectionBuffer = m_RTU.GetTemporaryRenderTexture(resolveDiffersFromTraceRes ? source.width : rtW, resolveDiffersFromTraceRes ? source.height : rtH, 0, intermediateFormat); + + material.SetFloat("_FresnelFade", settings.reflectionSettings.fresnelFade); + material.SetFloat("_FresnelFadePower", settings.reflectionSettings.fresnelFadePower); + material.SetFloat("_DistanceBlur", settings.reflectionSettings.distanceBlur); + material.SetInt("_HalfResolution", (settings.advancedSettings.resolution != SSRResolution.FullResolution) ? 1 : 0); + material.SetInt("_HighlightSuppression", settings.advancedSettings.highlightSuppression ? 1 : 0); + Graphics.Blit(reflectionBuffers[0], finalReflectionBuffer, material, (int)PassIndex.CompositeSSR); + material.SetTexture("_FinalReflectionTexture", finalReflectionBuffer); + + + RenderTexture temporallyFilteredBuffer = m_RTU.GetTemporaryRenderTexture(resolveDiffersFromTraceRes ? source.width : rtW, resolveDiffersFromTraceRes ? source.height : rtH, 0, intermediateFormat); + if (doTemporalFilterThisFrame) + { + material.SetInt("_UseTemporalConfidence", settings.advancedSettings.useTemporalConfidence ? 1 : 0); + material.SetFloat("_TemporalAlpha", settings.advancedSettings.temporalFilterStrength); + material.SetMatrix("_CurrentCameraToPreviousCamera", m_PreviousWorldToCameraMatrix * cameraToWorldMatrix); + material.SetTexture("_PreviousReflectionTexture", m_PreviousReflectionBuffer); + material.SetTexture("_PreviousCSZBuffer", m_PreviousDepthBuffer); + Graphics.Blit(source, temporallyFilteredBuffer, material, (int)PassIndex.TemporalFilter); + + material.SetTexture("_FinalReflectionTexture", temporallyFilteredBuffer); + } + + if (settings.advancedSettings.temporalFilterStrength > 0.0) + { + m_PreviousWorldToCameraMatrix = worldToCameraMatrix; + PreparePreviousBuffers(source.width, source.height); + Graphics.Blit(source, m_PreviousDepthBuffer, material, (int)PassIndex.BlitDepthAsCSZ); + Graphics.Blit(rayHitTexture, m_PreviousHitBuffer); + Graphics.Blit(doTemporalFilterThisFrame ? temporallyFilteredBuffer : finalReflectionBuffer, m_PreviousReflectionBuffer); + + m_HasInformationFromPreviousFrame = true; + } + + + Graphics.Blit(source, destination, material, (int)PassIndex.CompositeFinal); + + m_RTU.ReleaseAllTemporaryRenderTextures(); + } + } +} diff --git a/Assets/Cinematic Effects/ScreenSpaceReflection/ScreenSpaceReflection.cs.meta b/Assets/Cinematic Effects/ScreenSpaceReflection/ScreenSpaceReflection.cs.meta new file mode 100644 index 0000000..ae1741a --- /dev/null +++ b/Assets/Cinematic Effects/ScreenSpaceReflection/ScreenSpaceReflection.cs.meta @@ -0,0 +1,13 @@ +fileFormatVersion: 2 +guid: da3ff4a1bef2e8d47a1dfb734aa54de1 +timeCreated: 1433488439 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: + - ssrShader: {fileID: 4800000, guid: 7e2fcc83af19e744787647ec0ac5d42c, type: 3} + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/TonemappingColorGrading.meta b/Assets/Cinematic Effects/TonemappingColorGrading.meta new file mode 100644 index 0000000..d912b32 --- /dev/null +++ b/Assets/Cinematic Effects/TonemappingColorGrading.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 33083b2f3c4953846890c256af8cc606 +folderAsset: yes +timeCreated: 1435676891 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/TonemappingColorGrading/Editor.meta b/Assets/Cinematic Effects/TonemappingColorGrading/Editor.meta new file mode 100644 index 0000000..4307c22 --- /dev/null +++ b/Assets/Cinematic Effects/TonemappingColorGrading/Editor.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: a232fdc401b30b549b2ac3a54d76f6cc +folderAsset: yes +timeCreated: 1448359112 +licenseType: Pro +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/TonemappingColorGrading/Editor/TonemappingColorGradingEditor.cs b/Assets/Cinematic Effects/TonemappingColorGrading/Editor/TonemappingColorGradingEditor.cs new file mode 100644 index 0000000..1e4dfec --- /dev/null +++ b/Assets/Cinematic 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.Advanced; + 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/Assets/Cinematic Effects/TonemappingColorGrading/Editor/TonemappingColorGradingEditor.cs.meta b/Assets/Cinematic Effects/TonemappingColorGrading/Editor/TonemappingColorGradingEditor.cs.meta new file mode 100644 index 0000000..20e2686 --- /dev/null +++ b/Assets/Cinematic Effects/TonemappingColorGrading/Editor/TonemappingColorGradingEditor.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 64bb64b30a05a0d4b8afe58a356fc8fb +timeCreated: 1441354689 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/TonemappingColorGrading/Helpers.meta b/Assets/Cinematic Effects/TonemappingColorGrading/Helpers.meta new file mode 100644 index 0000000..ca560cb --- /dev/null +++ b/Assets/Cinematic Effects/TonemappingColorGrading/Helpers.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 54915b6fdd14fd042add2d153a8b892d +folderAsset: yes +timeCreated: 1454073138 +licenseType: Pro +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/TonemappingColorGrading/Helpers/NeutralLUT16.png b/Assets/Cinematic 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/Assets/Cinematic Effects/TonemappingColorGrading/Helpers/NeutralLUT16.png.meta b/Assets/Cinematic Effects/TonemappingColorGrading/Helpers/NeutralLUT16.png.meta new file mode 100644 index 0000000..45ff902 --- /dev/null +++ b/Assets/Cinematic Effects/TonemappingColorGrading/Helpers/NeutralLUT16.png.meta @@ -0,0 +1,57 @@ +fileFormatVersion: 2 +guid: 36c322ded1667bc4a867aea5e662c51b +timeCreated: 1454073156 +licenseType: Pro +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/Assets/Cinematic Effects/TonemappingColorGrading/Helpers/NeutralLUT32.png b/Assets/Cinematic 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/Assets/Cinematic Effects/TonemappingColorGrading/Helpers/NeutralLUT32.png.meta b/Assets/Cinematic Effects/TonemappingColorGrading/Helpers/NeutralLUT32.png.meta new file mode 100644 index 0000000..af95d9b --- /dev/null +++ b/Assets/Cinematic Effects/TonemappingColorGrading/Helpers/NeutralLUT32.png.meta @@ -0,0 +1,57 @@ +fileFormatVersion: 2 +guid: 6ac6980bae76ac241971e97191b6c30c +timeCreated: 1454073159 +licenseType: Pro +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/Assets/Cinematic Effects/TonemappingColorGrading/Resources.meta b/Assets/Cinematic Effects/TonemappingColorGrading/Resources.meta new file mode 100644 index 0000000..8d2bef2 --- /dev/null +++ b/Assets/Cinematic Effects/TonemappingColorGrading/Resources.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 710c12a933657234f859808d82c5dd8b +folderAsset: yes +timeCreated: 1453901184 +licenseType: Pro +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/TonemappingColorGrading/Resources/HistogramCompute.compute b/Assets/Cinematic Effects/TonemappingColorGrading/Resources/HistogramCompute.compute new file mode 100644 index 0000000..0e45d61 --- /dev/null +++ b/Assets/Cinematic 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/Assets/Cinematic Effects/TonemappingColorGrading/Resources/HistogramCompute.compute.meta b/Assets/Cinematic Effects/TonemappingColorGrading/Resources/HistogramCompute.compute.meta new file mode 100644 index 0000000..e276c48 --- /dev/null +++ b/Assets/Cinematic Effects/TonemappingColorGrading/Resources/HistogramCompute.compute.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 5ee4b74fa28a3e74e89423dd49705fc5 +timeCreated: 1436170077 +licenseType: Free +ComputeShaderImporter: + currentBuildTarget: 5 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/TonemappingColorGrading/Resources/HistogramRender.shader b/Assets/Cinematic Effects/TonemappingColorGrading/Resources/HistogramRender.shader new file mode 100644 index 0000000..c78673c --- /dev/null +++ b/Assets/Cinematic 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/Assets/Cinematic Effects/TonemappingColorGrading/Resources/HistogramRender.shader.meta b/Assets/Cinematic Effects/TonemappingColorGrading/Resources/HistogramRender.shader.meta new file mode 100644 index 0000000..5d62a23 --- /dev/null +++ b/Assets/Cinematic Effects/TonemappingColorGrading/Resources/HistogramRender.shader.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 9a8e838691462194482a43a02e424876 +timeCreated: 1436173774 +licenseType: Free +ShaderImporter: + defaultTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/TonemappingColorGrading/Resources/TonemappingColorGrading.cginc b/Assets/Cinematic Effects/TonemappingColorGrading/Resources/TonemappingColorGrading.cginc new file mode 100644 index 0000000..15d952c --- /dev/null +++ b/Assets/Cinematic Effects/TonemappingColorGrading/Resources/TonemappingColorGrading.cginc @@ -0,0 +1,246 @@ +#include "UnityCG.cginc" + +sampler2D _MainTex; +half4 _MainTex_TexelSize; + +half _Exposure; +half _ToneCurveRange; +sampler2D _ToneCurve; +half4 _NeutralTonemapperParams1; +half4 _NeutralTonemapperParams2; + +sampler2D _LutTex; +half4 _LutParams; + +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 uv, half3 scaleOffset) +{ + uv.z *= scaleOffset.z; + half shift = floor(uv.z); + uv.xy = uv.xy * scaleOffset.z * scaleOffset.xy + 0.5 * scaleOffset.xy; + uv.x += shift * scaleOffset.y; + uv.xyz = lerp(tex2D(tex, uv.xy).rgb, tex2D(tex, uv.xy + half2(scaleOffset.y, 0)).rgb, uv.z - shift); + return uv; +} + +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 GAMMA_COLORSPACE + 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 + half3 color_corrected = apply_lut(_LutTex, saturate(color.rgb), _LutParams.xyz); + color.rgb = lerp(color.rgb, color_corrected, _LutParams.w); +#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 GAMMA_COLORSPACE + color.rgb = LinearToGammaSpace(color.rgb); +#endif + + return color; +} diff --git a/Assets/Cinematic Effects/TonemappingColorGrading/Resources/TonemappingColorGrading.cginc.meta b/Assets/Cinematic Effects/TonemappingColorGrading/Resources/TonemappingColorGrading.cginc.meta new file mode 100644 index 0000000..30c5736 --- /dev/null +++ b/Assets/Cinematic Effects/TonemappingColorGrading/Resources/TonemappingColorGrading.cginc.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: a7e68b07525bc7f459ff03bf6cba782a +timeCreated: 1453723607 +licenseType: Pro +ShaderImporter: + defaultTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/TonemappingColorGrading/Resources/TonemappingColorGrading.shader b/Assets/Cinematic Effects/TonemappingColorGrading/Resources/TonemappingColorGrading.shader new file mode 100644 index 0000000..e25240c --- /dev/null +++ b/Assets/Cinematic Effects/TonemappingColorGrading/Resources/TonemappingColorGrading.shader @@ -0,0 +1,304 @@ +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" + + sampler2D _UserLutTex; + half4 _UserLutParams; + + 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; + + // User lut + contrib + half3 user_luted = apply_lut(_UserLutTex, final_lut, _UserLutParams.xyz); + final_lut = lerp(final_lut, user_luted, _UserLutParams.w); + + // 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 __ GAMMA_COLORSPACE + #pragma multi_compile __ ENABLE_COLOR_GRADING + #pragma multi_compile __ ENABLE_EYE_ADAPTATION + #pragma multi_compile __ ENABLE_DITHERING + #pragma fragment frag_tcg + #include "TonemappingColorGrading.cginc" + ENDCG + } + + // Tonemapping (ACES) + Pass + { + CGPROGRAM + #pragma multi_compile __ GAMMA_COLORSPACE + #pragma multi_compile __ ENABLE_COLOR_GRADING + #pragma multi_compile __ ENABLE_EYE_ADAPTATION + #pragma multi_compile __ ENABLE_DITHERING + #pragma fragment frag_tcg + #define TONEMAPPING_ACES + #include "TonemappingColorGrading.cginc" + ENDCG + } + + // Tonemapping (Curve) + Pass + { + CGPROGRAM + #pragma multi_compile __ GAMMA_COLORSPACE + #pragma multi_compile __ ENABLE_COLOR_GRADING + #pragma multi_compile __ ENABLE_EYE_ADAPTATION + #pragma multi_compile __ ENABLE_DITHERING + #pragma fragment frag_tcg + #define TONEMAPPING_CURVE + #include "TonemappingColorGrading.cginc" + ENDCG + } + + // Tonemapping (Hable) + Pass + { + CGPROGRAM + #pragma multi_compile __ GAMMA_COLORSPACE + #pragma multi_compile __ ENABLE_COLOR_GRADING + #pragma multi_compile __ ENABLE_EYE_ADAPTATION + #pragma multi_compile __ ENABLE_DITHERING + #pragma fragment frag_tcg + #define TONEMAPPING_HABLE + #include "TonemappingColorGrading.cginc" + ENDCG + } + + // Tonemapping (Hejl-Dawson) + Pass + { + CGPROGRAM + #pragma multi_compile __ GAMMA_COLORSPACE + #pragma multi_compile __ ENABLE_COLOR_GRADING + #pragma multi_compile __ ENABLE_EYE_ADAPTATION + #pragma multi_compile __ ENABLE_DITHERING + #pragma fragment frag_tcg + #define TONEMAPPING_HEJL_DAWSON + #include "TonemappingColorGrading.cginc" + ENDCG + } + + // Tonemapping (Photographic) + Pass + { + CGPROGRAM + #pragma multi_compile __ GAMMA_COLORSPACE + #pragma multi_compile __ ENABLE_COLOR_GRADING + #pragma multi_compile __ ENABLE_EYE_ADAPTATION + #pragma multi_compile __ ENABLE_DITHERING + #pragma fragment frag_tcg + #define TONEMAPPING_PHOTOGRAPHIC + #include "TonemappingColorGrading.cginc" + ENDCG + } + + // Tonemapping (Reinhard) + Pass + { + CGPROGRAM + #pragma multi_compile __ GAMMA_COLORSPACE + #pragma multi_compile __ ENABLE_COLOR_GRADING + #pragma multi_compile __ ENABLE_EYE_ADAPTATION + #pragma multi_compile __ ENABLE_DITHERING + #pragma fragment frag_tcg + #define TONEMAPPING_REINHARD + #include "TonemappingColorGrading.cginc" + ENDCG + } + + // Tonemapping (Neutral Hejl/Habble) + Pass + { + CGPROGRAM + #pragma multi_compile __ GAMMA_COLORSPACE + #pragma multi_compile __ ENABLE_COLOR_GRADING + #pragma multi_compile __ ENABLE_EYE_ADAPTATION + #pragma multi_compile __ ENABLE_DITHERING + #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/Assets/Cinematic Effects/TonemappingColorGrading/Resources/TonemappingColorGrading.shader.meta b/Assets/Cinematic Effects/TonemappingColorGrading/Resources/TonemappingColorGrading.shader.meta new file mode 100644 index 0000000..02d46ec --- /dev/null +++ b/Assets/Cinematic Effects/TonemappingColorGrading/Resources/TonemappingColorGrading.shader.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 964b34bbab7f5e64fa40f37eaccac1ad +timeCreated: 1435513939 +licenseType: Free +ShaderImporter: + defaultTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/TonemappingColorGrading/TonemappingColorGrading.cs b/Assets/Cinematic Effects/TonemappingColorGrading/TonemappingColorGrading.cs new file mode 100644 index 0000000..ff50805 --- /dev/null +++ b/Assets/Cinematic Effects/TonemappingColorGrading/TonemappingColorGrading.cs @@ -0,0 +1,1078 @@ +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 + { + + // 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; + + #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 LUTSettings m_Lut = LUTSettings.defaultSettings; + public LUTSettings lut + { + get { return m_Lut; } + set + { + m_Lut = value; + SetDirty(); + } + } + + [SerializeField, SettingsGroup] + private ColorGradingSettings m_ColorGrading = ColorGradingSettings.defaultSettings; + public ColorGradingSettings colorGrading + { + get { return m_ColorGrading; } + set + { + m_ColorGrading = value; + SetDirty(); + } + } + #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 + + if (isGammaColorSpace) + material.EnableKeyword("GAMMA_COLORSPACE"); + else + material.DisableKeyword("GAMMA_COLORSPACE"); + + material.DisableKeyword("ENABLE_EYE_ADAPTATION"); + material.DisableKeyword("ENABLE_COLOR_GRADING"); + material.DisableKeyword("ENABLE_DITHERING"); + + Texture lutUsed = null; + float lutContrib = 1f; + + 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 (lut.enabled) + { + Texture tex = lut.texture; + + if (lut.texture == null || !CheckUserLut()) + tex = identityLut; + + lutUsed = tex; + lutContrib = lut.contribution; + material.EnableKeyword("ENABLE_COLOR_GRADING"); + } + + if (colorGrading.enabled) + { + if (m_Dirty || !m_InternalLut.IsCreated()) + { + if (lutUsed == null) + { + material.SetVector("_UserLutParams", new Vector4(1f / identityLut.width, 1f / identityLut.height, identityLut.height - 1f, 1f)); + material.SetTexture("_UserLutTex", identityLut); + } + else + { + material.SetVector("_UserLutParams", new Vector4(1f / lutUsed.width, 1f / lutUsed.height, lutUsed.height - 1f, lut.contribution)); + material.SetTexture("_UserLutTex", lutUsed); + } + + 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; + } + + lutUsed = internalLutRt; + lutContrib = 1f; + material.EnableKeyword("ENABLE_COLOR_GRADING"); + + if (colorGrading.useDithering) + material.EnableKeyword("ENABLE_DITHERING"); + } + + if (lutUsed != null) + { + material.SetTexture("_LutTex", lutUsed); + material.SetVector("_LutParams", new Vector4(1f / lutUsed.width, 1f / lutUsed.height, lutUsed.height - 1f, lutContrib)); + } + + 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/Assets/Cinematic Effects/TonemappingColorGrading/TonemappingColorGrading.cs.meta b/Assets/Cinematic Effects/TonemappingColorGrading/TonemappingColorGrading.cs.meta new file mode 100644 index 0000000..ee75f55 --- /dev/null +++ b/Assets/Cinematic Effects/TonemappingColorGrading/TonemappingColorGrading.cs.meta @@ -0,0 +1,16 @@ +fileFormatVersion: 2 +guid: 58a7625302996c94ba07a8ca3351f668 +timeCreated: 1453901501 +licenseType: Pro +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/Assets/QuickRopes 2/CoreScripts.meta b/Assets/QuickRopes 2/CoreScripts.meta new file mode 100644 index 0000000..833154f --- /dev/null +++ b/Assets/QuickRopes 2/CoreScripts.meta @@ -0,0 +1,5 @@ +fileFormatVersion: 2 +guid: da2dd05291975a144870b1d17838eebc +folderAsset: yes +DefaultImporter: + userData: diff --git a/Assets/QuickRopes 2/CoreScripts/Editor.meta b/Assets/QuickRopes 2/CoreScripts/Editor.meta new file mode 100644 index 0000000..87ce869 --- /dev/null +++ b/Assets/QuickRopes 2/CoreScripts/Editor.meta @@ -0,0 +1,5 @@ +fileFormatVersion: 2 +guid: 5d08e488c9036014d88374d32b28ec1b +folderAsset: yes +DefaultImporter: + userData: diff --git a/Assets/QuickRopes 2/CoreScripts/Editor/QuickRope2ClothEditor.cs b/Assets/QuickRopes 2/CoreScripts/Editor/QuickRope2ClothEditor.cs new file mode 100644 index 0000000..56d1344 --- /dev/null +++ b/Assets/QuickRopes 2/CoreScripts/Editor/QuickRope2ClothEditor.cs @@ -0,0 +1,23 @@ +using UnityEngine; +using UnityEditor; +using System.Collections; + +[CustomEditor(typeof(QuickRope2Cloth))] +public class QuickRope2ClothEditor : Editor +{ + public const int MAX_CROSS_SEGMENTS = 24; + public const float MIN_RADIUS = 0.001f; + public const float MAX_RADIUS = 500; + + public override void OnInspectorGUI() + { + //QuickRope2Cloth t = (QuickRope2Cloth)target; + + //t.crossSegments = (int)Mathf.Clamp(t.crossSegments, 3, MAX_CROSS_SEGMENTS); + //t.maxRadius = (int)Mathf.Clamp(EditorGUILayout.IntField(new GUIContent("Max Radius", "The maximum radius allowed to be set by the curve."), t.maxRadius), 5, Mathf.Infinity); + //t.curve = EditorGUILayout.CurveField(new GUIContent("Radius Curve", "The ropes radius will be defined by the shape of this curve."), t.curve, Color.white, new Rect(0, 0, 1, t.maxRadius)); + + //if (GUI.changed) + // t.OnInitializeMesh(); + } +} \ No newline at end of file diff --git a/Assets/QuickRopes 2/CoreScripts/Editor/QuickRope2ClothEditor.cs.meta b/Assets/QuickRopes 2/CoreScripts/Editor/QuickRope2ClothEditor.cs.meta new file mode 100644 index 0000000..c4da37a --- /dev/null +++ b/Assets/QuickRopes 2/CoreScripts/Editor/QuickRope2ClothEditor.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: f079a7158988e7044a8b153dedb299e6 +labels: +- editor +- physics +- chain +- string +- cable +- reverie +- interactive +- quickropes +- gameplay +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/QuickRopes 2/CoreScripts/Editor/QuickRope2Editor.cs b/Assets/QuickRopes 2/CoreScripts/Editor/QuickRope2Editor.cs new file mode 100644 index 0000000..f386383 --- /dev/null +++ b/Assets/QuickRopes 2/CoreScripts/Editor/QuickRope2Editor.cs @@ -0,0 +1,612 @@ +using UnityEngine; +using UnityEditor; +using System.Collections; + +[CustomEditor(typeof(QuickRope2))] +public class QuickRope2Editor : Editor +{ + QuickRope2 r; + private int currentActiveHandle = -1; + private float guiScale = 0.5f; + private Vector3 prevRopePos = Vector3.zero; + + public const int MAX_CROSS_SEGMENTS = 24; + public const float MIN_RADIUS = 0.001f; + public const float MAX_RADIUS = 500; + + private Vector2 aoScrollPosition = Vector2.zero; + + void OnEnable() + { + r = (QuickRope2)target; + + if (Application.isPlaying) + return; + + CleanupObject(); + r.ApplyRopeSettings(); //r.SetControlPoints(r.ControlPoints); + } + + public override void OnInspectorGUI() + { + r.EDITOR_TAB_SELECTED = GUILayout.Toolbar(r.EDITOR_TAB_SELECTED, new string[] { "Basics", "Physics", "Attach", "Control" }); + EditorGUILayout.Separator(); + EditorGUILayout.Separator(); + + bool isCloth = (r.GetComponent() != null); + + switch (r.EDITOR_TAB_SELECTED) + { + case 0: + r.ropeEnd = (GameObject)EditorGUILayout.ObjectField(new GUIContent("Rope End", "The defined end of this rope."), r.ropeEnd, typeof(GameObject), true); + r.jointSpacing = EditorGUILayout.FloatField(new GUIContent("Joint Spacing", "The amount of distance between each joint in the rope object.\n\n Max = " + QuickRope2.MAX_JOINT_SPACING + "\n Min = " + QuickRope2.MIN_JOINT_SPACING + "\n\nTo set a custom the min/max distance, alter the const value in the QuickRopes2.cs script."), r.jointSpacing); + r.showJoints = EditorGUILayout.Toggle(new GUIContent("Preview Joints", "If checked, all joints created will be shown in the Hierarchy. Useful if you are trying to debug custom scripts."), r.showJoints); + QuickRope2.EDITOR_GUI_SCALE = EditorGUILayout.Slider("Editor GUI Scale", QuickRope2.EDITOR_GUI_SCALE, 0.1f, 5f); + guiScale = QuickRope2.EDITOR_GUI_SCALE; + + EditorGUILayout.Separator(); + EditorGUILayout.PrefixLabel("Set Mesh Type"); + EditorGUILayout.BeginHorizontal(); EditorGUILayout.Space(); int val = GUILayout.Toolbar(-1, new string[] { "None", "Line", "Prefab", "Mesh", "Cloth" }); EditorGUILayout.Space(); EditorGUILayout.EndHorizontal(); + switch (val) + { + case 0: + ClearMeshTypes(); + break; + case 1: + ClearMeshTypes(); + r.gameObject.AddComponent(); + break; + case 2: + ClearMeshTypes(); + r.gameObject.AddComponent(); + break; + case 3: + ClearMeshTypes(); + r.gameObject.AddComponent(); + break; + case 4: + ClearMeshTypes(); + r.gameObject.AddComponent(); + break; + } + + + EditorGUILayout.Separator(); + EditorGUILayout.Separator(); + EditorGUILayout.PrefixLabel("Mesh Type Settings"); + + if (r.GetComponent() != null) + { + EditorGUILayout.BeginHorizontal(); GUILayout.Space(35); EditorGUILayout.LabelField("Use \"Line Renderer\" component below."); EditorGUILayout.EndHorizontal(); + } + + if (r.GetComponent() != null) + { + QuickRope2Prefab t = r.GetComponent(); + + EditorGUILayout.BeginHorizontal(); GUILayout.Space(35); t.prefab = (GameObject)EditorGUILayout.ObjectField("Prefab", t.prefab, typeof(GameObject), false); EditorGUILayout.EndHorizontal(); + EditorGUILayout.BeginHorizontal(); GUILayout.Space(35); t.jointScale = EditorGUILayout.FloatField("Scale", t.jointScale); EditorGUILayout.EndHorizontal(); + + EditorGUILayout.BeginHorizontal(); GUILayout.Space(35); r.AlternateJoints = EditorGUILayout.Toggle("Alternate Joints", r.AlternateJoints); EditorGUILayout.EndHorizontal(); + if (r.AlternateJoints) + { + EditorGUILayout.BeginHorizontal(); + GUILayout.Space(35); + r.FirstJointAlternated = EditorGUILayout.Toggle("First Joint Alternated", r.FirstJointAlternated); + EditorGUILayout.EndHorizontal(); + } + } + + if(r.GetComponent()!=null) + { + QuickRope2Mesh t = r.GetComponent(); + + EditorGUILayout.BeginHorizontal(); GUILayout.Space(35); t.meshStatic = EditorGUILayout.Toggle(new GUIContent("Mesh Static", "If checked, the mesh will not automatically update during the \"Update\" method."), t.meshStatic); EditorGUILayout.EndHorizontal(); + EditorGUILayout.BeginHorizontal(); GUILayout.Space(35); t.crossSegments = (int)Mathf.Clamp(EditorGUILayout.IntField(new GUIContent("Sides", "The number of sides in your rope.\n\nMAX: " + MAX_CROSS_SEGMENTS), t.crossSegments), 3, MAX_CROSS_SEGMENTS); EditorGUILayout.EndHorizontal(); + EditorGUILayout.BeginHorizontal(); GUILayout.Space(35); t.maxRadius = (int)Mathf.Clamp(EditorGUILayout.IntField(new GUIContent("Curve Scale", "The scale of the curve graph below."), t.maxRadius), 1, Mathf.Infinity); EditorGUILayout.EndHorizontal(); + EditorGUILayout.BeginHorizontal(); GUILayout.Space(35); t.curve = EditorGUILayout.CurveField(new GUIContent("Radius Curve", "The ropes radius will be defined by the shape of this curve."), t.curve, Color.white, new Rect(0, 0, 1, t.maxRadius)); EditorGUILayout.EndHorizontal(); + EditorGUILayout.BeginHorizontal(); GUILayout.Space(35); t.textureTiling = EditorGUILayout.FloatField(new GUIContent("Texture Tiling", "Sets the Y value of the texture loaded on this rope."), t.textureTiling); EditorGUILayout.EndHorizontal(); + + } + + if (r.GetComponent() != null) + { + QuickRope2Cloth t = r.GetComponent(); + + EditorGUILayout.BeginHorizontal(); GUILayout.Space(35); t.crossSegments = (int)Mathf.Clamp(t.crossSegments, 3, MAX_CROSS_SEGMENTS); EditorGUILayout.EndHorizontal(); + EditorGUILayout.BeginHorizontal(); GUILayout.Space(35); t.maxRadius = (int)Mathf.Clamp(EditorGUILayout.IntField(new GUIContent("Max Radius", "The scale of the curve graph below."), t.maxRadius), 1, Mathf.Infinity); EditorGUILayout.EndHorizontal(); + EditorGUILayout.BeginHorizontal(); GUILayout.Space(35); t.curve = EditorGUILayout.CurveField(new GUIContent("Radius Curve", "The ropes radius will be defined by the shape of this curve."), t.curve, Color.white, new Rect(0, 0, 1, t.maxRadius)); EditorGUILayout.EndHorizontal(); + + } + + break; + + case 1: + /* BEGIN PHYSICS REGION */ + #region Physics + + if (r.enablePhysics && isCloth) + r.enablePhysics = false; + + if (isCloth) + { + GUILayout.Label("You cannot use traditional physics\non the Cloth type."); + EditorGUILayout.Separator(); + GUI.enabled = false; + } + + r.enablePhysics = EditorGUILayout.Toggle("Use Physics", r.enablePhysics); + + GUI.enabled = r.enablePhysics; + if (r.EDITOR_SHOW_RIGIDBODY = EditorGUILayout.Foldout(r.EDITOR_SHOW_RIGIDBODY, "Rigidbody Settings")) + { + EditorGUILayout.BeginHorizontal(); GUILayout.Space(25); r.constraint = (RopeConstraint)EditorGUILayout.EnumPopup(new GUIContent("Constraints", ""), r.constraint); EditorGUILayout.EndHorizontal(); + EditorGUILayout.BeginHorizontal(); GUILayout.Space(25); r.solverOverride = (int)Mathf.Clamp(EditorGUILayout.IntField(new GUIContent("Solver Override", ""), r.solverOverride), -1, 255); EditorGUILayout.EndHorizontal(); + EditorGUILayout.BeginHorizontal(); GUILayout.Space(25); r.mass = Mathf.Clamp(EditorGUILayout.FloatField(new GUIContent("Mass", ""), r.mass), 0.0001f, Mathf.Infinity); EditorGUILayout.EndHorizontal(); + EditorGUILayout.BeginHorizontal(); GUILayout.Space(25); r.drag = Mathf.Clamp(EditorGUILayout.FloatField(new GUIContent("Drag", ""), r.drag), 0, Mathf.Infinity); EditorGUILayout.EndHorizontal(); + EditorGUILayout.BeginHorizontal(); GUILayout.Space(25); r.angDrag = Mathf.Clamp(EditorGUILayout.FloatField(new GUIContent("Angular Drag", ""), r.angDrag), 0, Mathf.Infinity); EditorGUILayout.EndHorizontal(); + EditorGUILayout.BeginHorizontal(); GUILayout.Space(25); r.useGravity = EditorGUILayout.Toggle(new GUIContent("Use Gravity", ""), r.useGravity); EditorGUILayout.EndHorizontal(); + } + EditorGUILayout.Separator(); + + if (r.EDITOR_SHOW_JOINTSETTINGS = EditorGUILayout.Foldout(r.EDITOR_SHOW_JOINTSETTINGS, "Joint Settings")) + { + + EditorGUILayout.BeginHorizontal(); GUILayout.Space(25); r.LowAngXLimit = (r.AngYLimit = r.HighAngXLimit = Mathf.Clamp(EditorGUILayout.FloatField(new GUIContent("Swing Limit", ""), r.AngYLimit), 0, 180)) * -1; EditorGUILayout.EndHorizontal(); + EditorGUILayout.BeginHorizontal(); GUILayout.Space(40); r.LTLDamper = Mathf.Clamp(EditorGUILayout.FloatField(new GUIContent("Dampen", ""), r.LTLDamper), 0, 500); EditorGUILayout.EndHorizontal(); + EditorGUILayout.BeginHorizontal(); GUILayout.Space(40); r.LTLSpring = Mathf.Clamp(EditorGUILayout.FloatField(new GUIContent("Spring", ""), r.LTLSpring), 0, 500); EditorGUILayout.EndHorizontal(); + EditorGUILayout.BeginHorizontal(); GUILayout.Space(40); r.LTLBounce = Mathf.Clamp(EditorGUILayout.FloatField(new GUIContent("Bounce", ""), r.LTLBounce), 0, 500); EditorGUILayout.EndHorizontal(); + EditorGUILayout.Separator(); + + EditorGUILayout.BeginHorizontal(); GUILayout.Space(25); r.AngZLimit = Mathf.Clamp(EditorGUILayout.FloatField(new GUIContent("Twist Limit", ""), r.AngZLimit), 0, 180); EditorGUILayout.EndHorizontal(); + EditorGUILayout.BeginHorizontal(); GUILayout.Space(40); r.S1LDamper = Mathf.Clamp(EditorGUILayout.FloatField(new GUIContent("Dampen", ""), r.S1LDamper), 0, 500); EditorGUILayout.EndHorizontal(); + EditorGUILayout.BeginHorizontal(); GUILayout.Space(40); r.S1LSpring = Mathf.Clamp(EditorGUILayout.FloatField(new GUIContent("Spring", ""), r.S1LSpring), 0, 500); EditorGUILayout.EndHorizontal(); + EditorGUILayout.BeginHorizontal(); GUILayout.Space(40); r.S1LBounce = Mathf.Clamp(EditorGUILayout.FloatField(new GUIContent("Bounce", ""), r.S1LBounce), 0, 500); EditorGUILayout.EndHorizontal(); + EditorGUILayout.Separator(); + + GUI.enabled = ((r.GetComponent() == null) && (r.GetComponent() == null) && (r.GetComponent() == null)); + EditorGUILayout.BeginHorizontal(); GUILayout.Space(25); r.breakForce = Mathf.Clamp(EditorGUILayout.FloatField(new GUIContent("Break Force", ""), r.breakForce), 0, Mathf.Infinity); EditorGUILayout.EndHorizontal(); + EditorGUILayout.BeginHorizontal(); GUILayout.Space(25); r.breakTorque = Mathf.Clamp(EditorGUILayout.FloatField(new GUIContent("Break Torque", ""), r.breakTorque), 0, Mathf.Infinity); EditorGUILayout.EndHorizontal(); + GUI.enabled = true; + } + EditorGUILayout.Separator(); + + if (r.EDITOR_SHOW_COLLIDERSETTINGS = EditorGUILayout.Foldout(r.EDITOR_SHOW_COLLIDERSETTINGS, "Collider Settings")) + { + EditorGUILayout.BeginHorizontal(); GUILayout.Space(25); r.colliderType = (RopeColliderType)EditorGUILayout.EnumPopup(new GUIContent("Collider Type", ""), r.colliderType); EditorGUILayout.EndHorizontal(); + GUI.enabled = (r.colliderType != RopeColliderType.DEFAULT); + EditorGUILayout.BeginHorizontal(); GUILayout.Space(25); r.colliderRadius = Mathf.Clamp(EditorGUILayout.FloatField(new GUIContent("Collider Radius", ""), r.colliderRadius), 0, Mathf.Infinity); EditorGUILayout.EndHorizontal(); + EditorGUILayout.BeginHorizontal(); GUILayout.Space(25); r.physicsMaterial = (PhysicMaterial)EditorGUILayout.ObjectField(new GUIContent("Physics Material", ""), r.physicsMaterial, typeof(PhysicMaterial), false); EditorGUILayout.EndHorizontal(); + GUI.enabled = true; + } + GUI.enabled = true; + #endregion + + break; + case 2: + if (isCloth) + { + GUILayout.Label("You must attach objects via the \n\"Interactive Cloth\" component below."); + EditorGUILayout.Separator(); + GUI.enabled = false; + } + + if (GUILayout.Button(new GUIContent("Attach GameObject", "Adds a new attachment variable. Assign the variable with the object you would like to attach and the joint index you would like your object to attach to. Attachment is represented by a blue arrow pointing from object to joint index in the scene."))) + { + r.attachedObjects.Add(new RopeAttachedObject()); + } + + EditorGUILayout.Separator(); + + if (r.attachedObjects.Count == 0) + { + EditorGUILayout.Separator(); + EditorGUILayout.Separator(); + EditorGUILayout.LabelField("No objects have been attached.\n\nPress \"Attach GameObject\" button above.", GUILayout.Height(55)); + } + + aoScrollPosition = GUILayout.BeginScrollView(aoScrollPosition, GUILayout.MaxHeight(200), GUILayout.MinHeight(200)); + foreach (RopeAttachedObject ao in r.attachedObjects) + { + EditorGUILayout.BeginHorizontal(); GUILayout.Space(5); ao.go = (GameObject)EditorGUILayout.ObjectField((ao.go==null) ? "Object" : ao.go.name, ao.go, typeof(GameObject), true); EditorGUILayout.EndHorizontal(); + EditorGUILayout.BeginHorizontal(); GUILayout.Space(25); ao.jointType = (RopeAttachmentJointType)EditorGUILayout.EnumPopup("Con. Type", ao.jointType); EditorGUILayout.EndHorizontal(); + + if (ao.jointType == RopeAttachmentJointType.Hinge) + { + EditorGUILayout.BeginHorizontal(); GUILayout.Space(35); ao.hingeAxis = EditorGUILayout.Vector3Field("Axis", ao.hingeAxis); EditorGUILayout.EndHorizontal(); + } + + EditorGUILayout.BeginHorizontal(); GUILayout.Space(25); ao.jointIndex = (int)Mathf.Clamp(EditorGUILayout.IntField("Index", ao.jointIndex), 0, r.Joints.Count-1); EditorGUILayout.EndHorizontal(); + + EditorGUILayout.BeginHorizontal(); + if (ao.go != null) + { + GUILayout.Space(Screen.width / 3f); if (GUILayout.Button("Center On Index")) { ao.go.transform.position = r.Joints[ao.jointIndex].transform.position; } + } + if (GUILayout.Button("Remove")) { r.attachedObjects.Remove(ao); r.attachedObjects.TrimExcess(); return; } + EditorGUILayout.EndHorizontal(); + EditorGUILayout.Space(); + } + GUILayout.EndScrollView(); + GUI.enabled = true; + break; + + case 3: + + if (r.enablePhysics && isCloth) + r.enablePhysics = false; + + if (isCloth) + { + GUILayout.Label("You cannot use the controller\non the Cloth type."); + EditorGUILayout.Separator(); + r.enableRopeController = false; + GUI.enabled = false; + } + + r.enableRopeController = EditorGUILayout.Toggle(new GUIContent("Enable Conroller", ""), r.enableRopeController); + EditorGUILayout.Separator(); + + GUI.enabled = r.enableRopeController; + EditorGUILayout.BeginHorizontal(); GUILayout.Space(25); r.extendRopeKey = (KeyCode)EditorGUILayout.EnumPopup(new GUIContent("Extend Key", ""), r.extendRopeKey); EditorGUILayout.EndHorizontal(); + EditorGUILayout.BeginHorizontal(); GUILayout.Space(25); r.retractRopeKey = (KeyCode)EditorGUILayout.EnumPopup(new GUIContent("Retract Key", ""), r.retractRopeKey); EditorGUILayout.EndHorizontal(); + + EditorGUILayout.Separator(); + EditorGUILayout.BeginHorizontal(); GUILayout.Space(25); EditorGUILayout.LabelField("Current Rope Length: " + r.RopeLength); EditorGUILayout.EndHorizontal(); + EditorGUILayout.BeginHorizontal(); GUILayout.Space(25); r.maxRopeLength = Mathf.Clamp(EditorGUILayout.FloatField(new GUIContent("Max Length", ""), r.maxRopeLength), r.jointSpacing * 3f, Mathf.Infinity); EditorGUILayout.EndHorizontal(); + EditorGUILayout.BeginHorizontal(); GUILayout.Space(25); r.minRopeLength = Mathf.Clamp(EditorGUILayout.FloatField(new GUIContent("Min Length", ""), r.minRopeLength), r.jointSpacing * 3f, Mathf.Infinity); EditorGUILayout.EndHorizontal(); + + EditorGUILayout.Separator(); + EditorGUILayout.BeginHorizontal(); GUILayout.Space(25); r.acceleration = Mathf.Clamp(EditorGUILayout.FloatField(new GUIContent("Acceleration", ""), r.acceleration), 0, Mathf.Infinity); EditorGUILayout.EndHorizontal(); + EditorGUILayout.BeginHorizontal(); GUILayout.Space(25); r.dampening = Mathf.Clamp(EditorGUILayout.FloatField(new GUIContent("Dampening", ""), r.dampening), 0, 1); EditorGUILayout.EndHorizontal(); + EditorGUILayout.BeginHorizontal(); GUILayout.Space(25); r.maxVelocity = Mathf.Clamp(EditorGUILayout.FloatField(new GUIContent("Max Velocity", ""), r.maxVelocity), 0, Mathf.Infinity); EditorGUILayout.EndHorizontal(); + EditorGUILayout.BeginHorizontal(); GUILayout.Space(25); r.sleepVelocity = Mathf.Clamp(EditorGUILayout.FloatField(new GUIContent("Sleep Velocity", ""), r.sleepVelocity), 0, Mathf.Infinity); EditorGUILayout.EndHorizontal(); + + EditorGUILayout.Separator(); + + GUI.enabled = true; + break; + } + + EditorGUILayout.Separator(); + EditorGUILayout.Separator(); + + if (!Application.isPlaying && GUI.changed) + UpdateRope(); + } + + void CleanupObject() + { + if (r.ropeEnd == null) + return; + + if (!r.enablePhysics) + { + DestroyImmediate(r.ropeEnd.GetComponent()); + DestroyImmediate(r.ropeEnd.GetComponent()); + DestroyImmediate(r.GetComponent()); + DestroyImmediate(r.GetComponent()); + } + + if (r.GetComponent() == null) + { + DestroyImmediate(r.GetComponent()); + } + + if (r.GetComponent() == null) + { + //if(r.GetComponent()==null) + // DestroyImmediate(r.GetComponent()); + + DestroyImmediate(r.GetComponent()); + DestroyImmediate(r.GetComponent()); + } + + if (r.GetComponent() == null) + { + //if (r.GetComponent() == null) + // DestroyImmediate(r.GetComponent()); + + DestroyImmediate(r.GetComponent()); + DestroyImmediate(r.GetComponent()); + } + } + + void ClearMeshTypes() + { + if (r.GetComponent()) + { + DestroyImmediate(r.GetComponent()); + } + + if (r.GetComponent()) + { + DestroyImmediate(r.GetComponent()); + } + + if (r.GetComponent()) + { + DestroyImmediate(r.GetComponent()); + } + + if (r.GetComponent()) + { + DestroyImmediate(r.GetComponent()); + } + } + + bool rebuildAfterCompile = false; + void OnSceneGUI() + { + r = (QuickRope2)target; + if (Application.isPlaying || r.ropeEnd == null) + return; + + if (EditorApplication.isCompiling) + { + rebuildAfterCompile = true; + } + else if (rebuildAfterCompile) + { + rebuildAfterCompile = false; + UpdateRope(); + //return; + } + + Quaternion camLookAt = SceneView.currentDrawingSceneView.camera.transform.rotation; + Vector3 camNormal = SceneView.currentDrawingSceneView.camera.transform.forward; + + + //============== Add Control Point Button ================== + + if (r.ControlPoints.Count == 0 && PlusButton(r.transform.position + (r.ropeEnd.transform.position - r.transform.position) / 2, camLookAt)) + { + r.ControlPoints.Add(r.transform.position + (r.ropeEnd.transform.position - r.transform.position) / 2); + } + + if(r.ControlPoints.Count > 0) + { + // First Add Button + if (PlusButton(r.transform.position + (r.ControlPoints[0] - r.transform.position)/2, camLookAt)) + { + r.ControlPoints.Insert(0, r.transform.position + (r.ControlPoints[0] - r.transform.position) / 2); + currentActiveHandle = 0; + } + + // Last Add Button + if (PlusButton(r.ControlPoints[r.ControlPoints.Count - 1] + (r.ropeEnd.transform.position - r.ControlPoints[r.ControlPoints.Count-1])/2, camLookAt)) + { + r.ControlPoints.Insert(r.ControlPoints.Count, r.ControlPoints[r.ControlPoints.Count - 1] + (r.ropeEnd.transform.position - r.ControlPoints[r.ControlPoints.Count - 1]) / 2); + currentActiveHandle = r.ControlPoints.Count - 1; + } + + for (int i = 0; i < r.ControlPoints.Count - 1; i++) + { + Vector3 btnPos = r.ControlPoints[i] + ((r.ControlPoints[i + 1] - r.ControlPoints[i]) / 2); + + if (PlusButton(btnPos, camLookAt)) + { + r.ControlPoints.Insert(i + 1, btnPos); + currentActiveHandle = i + 1; + } + } + } + + // ================== + if (r.ControlPoints == null) + { + UpdateRope(); + return; + } + + // ================= + for (int i = 0; i < r.ControlPoints.Count; i++) + { + Handles.color = new Color(0, 0, 0, 1); + if (Handles.Button(r.ControlPoints[i], camLookAt, 0.5f * guiScale, 0.5f * guiScale, Handles.CircleCap)) + currentActiveHandle = i; + + if (i == currentActiveHandle) + { + Handles.color = new Color(0.3f, 0.3f, 0.8f); + Handles.DrawSolidDisc(r.ControlPoints[i], camNormal, 0.4f * guiScale); + + Handles.color = Color.white; + r.ControlPoints[i] = Handles.PositionHandle(r.ControlPoints[i], Quaternion.identity); + + if (Event.current.type == EventType.keyDown) + { + if (Event.current.keyCode == KeyCode.P) + { + if (i > 0 && i < r.ControlPoints.Count - 2) + r.ControlPoints.Insert(i + 1, r.ControlPoints[i] + ((r.ControlPoints[i + 1] - r.ControlPoints[i]) / 2)); + //UpdateRope(); + } + + if (Event.current.keyCode == KeyCode.Backspace) + { + r.ControlPoints.RemoveAt(currentActiveHandle); + + currentActiveHandle--; + if (currentActiveHandle == -1 && r.ControlPoints.Count != 0) + currentActiveHandle = 0; + + r.ControlPoints.TrimExcess(); + UpdateRope(); + return; + } + } + } + else + { + Handles.color = new Color(0.2f, 0.2f, 0.4f, 0.8f); + Handles.DrawSolidDisc(r.ControlPoints[i], camNormal, 0.4f * guiScale); + } + } + + //Deal with rope end + { + Handles.color = new Color(0, 0, 0, 1); + if (Handles.Button(r.ropeEnd.transform.position, camLookAt, 0.5f * guiScale, 0.5f * guiScale, Handles.CircleCap)) + currentActiveHandle = 5000; + + if (currentActiveHandle == 5000) + + { + Handles.color = new Color(0.3f, 0.3f, 0.8f); + Handles.DrawSolidDisc(r.ropeEnd.transform.position, camNormal, 0.4f * guiScale); + + Handles.color = Color.white; + r.ropeEnd.transform.position = Handles.PositionHandle(r.ropeEnd.transform.position, Quaternion.identity); + } + else + { + Handles.color = new Color(0.2f, 0.2f, 0.4f, 0.8f); + Handles.DrawSolidDisc(r.ropeEnd.transform.position, camNormal, 0.4f * guiScale); + } + } + + foreach (RopeAttachedObject ao in r.attachedObjects) + { + if (ao.go == null) + continue; + + if (ao.jointIndex > r.Joints.Count - 1) + ao.jointIndex = r.Joints.Count - 1; + + Handles.color = new Color(0.8f, 0.4f, 0f, 0.8f); + Handles.DrawSolidDisc(ao.go.transform.position, camNormal, 0.2f * guiScale); + Handles.DrawSolidDisc(r.Joints[ao.jointIndex].transform.position, camNormal, 0.2f * guiScale); + + float dist = Vector3.Distance(r.Joints[ao.jointIndex].transform.position, ao.go.transform.position); + + if (dist > 0.5f) + Handles.ArrowCap(0, ao.go.transform.position, Quaternion.LookRotation((r.Joints[ao.jointIndex].transform.position - ao.go.transform.position).normalized), dist * 0.8f); + + Handles.color = new Color(0.8f, 0f, 0f, 0.8f); + if (ao.jointType == RopeAttachmentJointType.Hinge && (ao.hingeAxis != Vector3.zero)) + Handles.ArrowCap(0, ao.go.transform.position, ao.go.transform.rotation * Quaternion.LookRotation(ao.hingeAxis), 1); + } + + winRect = GUI.Window(0, winRect, EditWindowFunc, "Edit Selected Control Point"); + + if (GUI.changed) + { + EditorUtility.SetDirty(target); + UpdateRope(); + } + else if (QuickRope2Helper.HasMoved(ref prevRopePos, r.transform.position)) + UpdateRope(); + } + + void UpdateRope() + { + r.jointSpacing = Mathf.Clamp(r.jointSpacing, QuickRope2.MIN_JOINT_SPACING, QuickRope2.MAX_JOINT_SPACING); + if (r.jointSpacing >= QuickRope2.MIN_JOINT_SPACING) + { + r.ApplyRopeSettings(); //r.SetControlPoints(r.ControlPoints); + } + } + + bool PlusButton(Vector3 position, Quaternion direction) + { + Handles.color = new Color(0, 0.8f, 0, 1f); + Handles.DotCap(0, position, direction, 0.2f * guiScale); + return Handles.Button(position, direction, 0.25f * guiScale, 0.25f * guiScale, Handles.RectangleCap); + } + + Vector3 curSelVect = Vector3.zero; + static Rect winRect = new Rect(5, 25, 260, 125); + void EditWindowFunc(int winID) + { + if (currentActiveHandle < 0) + { + GUI.Label(new Rect(45, 55, 260, 125), "Add or select a control point!"); + return; + } + + if (currentActiveHandle == 5000) + curSelVect = r.ropeEnd.transform.position; + else + curSelVect = r.ControlPoints[currentActiveHandle]; + + EditorGUILayout.BeginHorizontal(); + GUILayout.Space(30); + EditorGUILayout.LabelField("X: ", GUILayout.Width(50)); + float x = EditorGUILayout.FloatField(curSelVect.x, GUILayout.Width(150)); + EditorGUILayout.EndHorizontal(); + + EditorGUILayout.BeginHorizontal(); + GUILayout.Space(30); + EditorGUILayout.LabelField("Y: ", GUILayout.Width(50)); + float y = EditorGUILayout.FloatField(curSelVect.y, GUILayout.Width(150)); + EditorGUILayout.EndHorizontal(); + + EditorGUILayout.BeginHorizontal(); + GUILayout.Space(30); + EditorGUILayout.LabelField("Z: ", GUILayout.Width(50)); + float z = EditorGUILayout.FloatField(curSelVect.z, GUILayout.Width(150)); + EditorGUILayout.EndHorizontal(); + + if (currentActiveHandle == 5000) + { + r.ropeEnd.transform.position = new Vector3(x, y, z); + GUI.enabled = false; + } + else + { + r.ControlPoints[currentActiveHandle] = new Vector3(x, y, z); + } + + EditorGUILayout.Space(); + + GUILayout.BeginHorizontal(); + if (GUILayout.Button("Average")) + { + if (r.ControlPoints.Count == 1) + { + r.ControlPoints[currentActiveHandle] = (r.ropeEnd.transform.position - r.transform.position) / 2f; + } + else + { + if (currentActiveHandle > 0 && currentActiveHandle < (r.ControlPoints.Count-1)) + { + r.ControlPoints[currentActiveHandle] = (r.ControlPoints[currentActiveHandle - 1] + r.ControlPoints[currentActiveHandle + 1]) / 2f; + } + else if(currentActiveHandle == 0) + { + r.ControlPoints[currentActiveHandle] = (r.transform.position + r.ControlPoints[currentActiveHandle + 1]) / 2f; + } + else if(currentActiveHandle == (r.ControlPoints.Count-1)) + { + r.ControlPoints[currentActiveHandle] = (r.ControlPoints[currentActiveHandle - 1] + r.ropeEnd.transform.position) / 2f; + } + } + + UpdateRope(); + } + if (GUILayout.Button("Zero Vector")) + { + r.ControlPoints[currentActiveHandle] = Vector3.zero; + UpdateRope(); + } + GUILayout.EndHorizontal(); + if (GUILayout.Button("Delete [Backspace]")) + { + r.ControlPoints.RemoveAt(currentActiveHandle); + + currentActiveHandle--; + if (currentActiveHandle == -1 && r.ControlPoints.Count != 0) + currentActiveHandle = 0; + + r.ControlPoints.TrimExcess(); + UpdateRope(); + } + + if (GUI.changed) + UpdateRope(); + + GUI.enabled = true; + GUI.DragWindow(); + } +} diff --git a/Assets/QuickRopes 2/CoreScripts/Editor/QuickRope2Editor.cs.meta b/Assets/QuickRopes 2/CoreScripts/Editor/QuickRope2Editor.cs.meta new file mode 100644 index 0000000..55a5725 --- /dev/null +++ b/Assets/QuickRopes 2/CoreScripts/Editor/QuickRope2Editor.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 23701cc23be2f004f92e9acdb9a3ad62 +labels: +- editor +- physics +- chain +- string +- cable +- reverie +- interactive +- quickropes +- gameplay +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/QuickRopes 2/CoreScripts/Editor/QuickRope2Menu.cs b/Assets/QuickRopes 2/CoreScripts/Editor/QuickRope2Menu.cs new file mode 100644 index 0000000..c81083d --- /dev/null +++ b/Assets/QuickRopes 2/CoreScripts/Editor/QuickRope2Menu.cs @@ -0,0 +1,134 @@ +using UnityEngine; +using UnityEditor; +using System.Collections; + +public class QuickRope2Menu : MonoBehaviour +{ + [MenuItem("QuickRopes/Ropes/Line Rope")] + static void AddBasicLineRope() + { + QuickRope2 r = QuickRope2.Create(new Vector3(-5, 0, 0), new Vector3(5, 0, 0), BasicRopeTypes.Line); + r.gameObject.name = "Line_Rope_Start"; + r.ropeEnd.name = "Line_Rope_End"; + Selection.activeGameObject = r.gameObject; + } + + [MenuItem("QuickRopes/Ropes/Mesh Rope")] + static void AddBasicMeshRope() + { + QuickRope2 r = QuickRope2.Create(new Vector3(-5, 0, 0), new Vector3(5, 0, 0), BasicRopeTypes.Mesh); + r.gameObject.name = "Mesh_Rope_Start"; + r.ropeEnd.name = "Mesh_Rope_End"; + Selection.activeGameObject = r.gameObject; + } + + [MenuItem("QuickRopes/Ropes/Prefab Rope")] + static void AddBasicPrefabRope() + { + QuickRope2 r = QuickRope2.Create(new Vector3(-5, 0, 0), new Vector3(5, 0, 0), BasicRopeTypes.Prefab); + r.gameObject.name = "Prefab_Rope_Start"; + r.ropeEnd.name = "Prefab_Rope_End"; + Selection.activeGameObject = r.gameObject; + } + + [MenuItem("QuickRopes/Ropes/Cloth Rope")] + static void AddBasicClothRope() + { + QuickRope2 r = QuickRope2.Create(new Vector3(-5, 0, 0), new Vector3(5, 0, 0), BasicRopeTypes.Cloth); + r.gameObject.name = "Cloth_Rope_Start"; + r.ropeEnd.name = "Cloth_Rope_End"; + Selection.activeGameObject = r.gameObject; + } + + [MenuItem("QuickRopes/Switch Mesh/Set As Line Type")] + static void SetLine() + { + CleanupObject(); + Selection.activeGameObject.AddComponent(); + } + [MenuItem("QuickRopes/Switch Mesh/Set As Line Type", true)] + static bool ValidateSetLine() + { + return ValidateQR2(); + } + + [MenuItem("QuickRopes/Switch Mesh/Set As Mesh Type")] + static void SetMesh() + { + CleanupObject(); + Selection.activeGameObject.AddComponent(); + } + [MenuItem("QuickRopes/Switch Mesh/Set As Mesh Type", true)] + static bool ValidateSetMesh() + { + return ValidateQR2(); + } + + [MenuItem("QuickRopes/Switch Mesh/Set As Prefab Type")] + static void SetPrefab() + { + CleanupObject(); + Selection.activeGameObject.AddComponent(); + } + [MenuItem("QuickRopes/Switch Mesh/Set As Prefab Type", true)] + static bool ValidateSetPrefab() + { + return ValidateQR2(); + } + + [MenuItem("QuickRopes/Switch Mesh/Set As Cloth Type")] + static void SetCloth() + { + CleanupObject(); + Selection.activeGameObject.AddComponent(); + } + [MenuItem("QuickRopes/Switch Mesh/Set As Cloth Type", true)] + static bool ValidateSetCloth() + { + return ValidateQR2(); + } + + [MenuItem("QuickRopes/More ->/Video Tutorials")] + static void GotoVids() + { + Application.OpenURL("http://reverieinteractive.com/unity-assets/quickropes/quickropes-video-tutorials"); + } + + [MenuItem("QuickRopes/More ->/Text Tutorials")] + static void GotoAPI() + { + Application.OpenURL("http://reverieinteractive.com/unity-assets/quickropes/quickropes-scripting-examples"); + } + + static void CleanupObject() + { + QuickRope2 r = Selection.activeGameObject.GetComponent(); + + if (r.GetComponent()) + { + DestroyImmediate(r.GetComponent()); + } + + if (r.GetComponent()) + { + DestroyImmediate(r.GetComponent()); + } + + if (r.GetComponent()) + { + DestroyImmediate(r.GetComponent()); + } + + if (r.GetComponent()) + { + DestroyImmediate(r.GetComponent()); + } + } + static bool ValidateQR2() + { + if (Selection.activeGameObject == null) + return false; + + return Selection.activeGameObject.GetComponent() != null; + } +} diff --git a/Assets/QuickRopes 2/CoreScripts/Editor/QuickRope2Menu.cs.meta b/Assets/QuickRopes 2/CoreScripts/Editor/QuickRope2Menu.cs.meta new file mode 100644 index 0000000..4529280 --- /dev/null +++ b/Assets/QuickRopes 2/CoreScripts/Editor/QuickRope2Menu.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: ee660ef9367dc564a8e1095c459109a3 +labels: +- editor +- physics +- chain +- string +- cable +- reverie +- interactive +- quickropes +- gameplay +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/QuickRopes 2/CoreScripts/Editor/QuickRope2MeshEditor.cs b/Assets/QuickRopes 2/CoreScripts/Editor/QuickRope2MeshEditor.cs new file mode 100644 index 0000000..22ef6ad --- /dev/null +++ b/Assets/QuickRopes 2/CoreScripts/Editor/QuickRope2MeshEditor.cs @@ -0,0 +1,24 @@ +using UnityEngine; +using UnityEditor; +using System.Collections; + +[CustomEditor(typeof(QuickRope2Mesh))] +public class QuickRope2MeshEditor : Editor +{ + public override void OnInspectorGUI() + { + /* + QuickRope2Mesh t = (QuickRope2Mesh)target; + + t.meshStatic = EditorGUILayout.Toggle(new GUIContent("Mesh Static","If checked, the mesh will not automatically update during the \"Update\" method."), t.meshStatic); + t.crossSegments = (int)Mathf.Clamp(EditorGUILayout.IntField(new GUIContent("Sides", "The number of sides in your rope.\n\nMAX: " + MAX_CROSS_SEGMENTS), t.crossSegments), 3, MAX_CROSS_SEGMENTS); + t.maxRadius = (int)Mathf.Clamp(EditorGUILayout.IntField(new GUIContent("Max Radius","The maximum radius allowed to be set by the curve."), t.maxRadius), 5, Mathf.Infinity); + t.curve = EditorGUILayout.CurveField(new GUIContent("Radius Curve","The ropes radius will be defined by the shape of this curve."), t.curve, Color.white, new Rect(0, 0, 1, t.maxRadius)); + t.textureTiling = EditorGUILayout.FloatField(new GUIContent("Texture Tiling", "Sets the Y value of the texture loaded on this rope."), t.textureTiling); + + if (GUI.changed) + t.OnInitializeMesh(); + + */ + } +} diff --git a/Assets/QuickRopes 2/CoreScripts/Editor/QuickRope2MeshEditor.cs.meta b/Assets/QuickRopes 2/CoreScripts/Editor/QuickRope2MeshEditor.cs.meta new file mode 100644 index 0000000..2fdc206 --- /dev/null +++ b/Assets/QuickRopes 2/CoreScripts/Editor/QuickRope2MeshEditor.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 2654b7af2fc50fb46b76cdfddeff5ee7 +labels: +- editor +- physics +- chain +- string +- cable +- reverie +- interactive +- quickropes +- gameplay +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/QuickRopes 2/CoreScripts/Editor/QuickRope2PrefabEditor.cs b/Assets/QuickRopes 2/CoreScripts/Editor/QuickRope2PrefabEditor.cs new file mode 100644 index 0000000..5213c3e --- /dev/null +++ b/Assets/QuickRopes 2/CoreScripts/Editor/QuickRope2PrefabEditor.cs @@ -0,0 +1,25 @@ +using UnityEngine; +using UnityEditor; +using System.Collections; + +[CustomEditor(typeof(QuickRope2Prefab))] +public class QuickRope2PrefabEditor : Editor +{ + public override void OnInspectorGUI() + { + //QuickRope2Prefab t = (QuickRope2Prefab)target; + + //t.prefab = (GameObject)EditorGUILayout.ObjectField("Prefab", t.prefab, typeof(GameObject), false); + //t.jointScale = EditorGUILayout.FloatField("Scale", t.jointScale); + //if (t.alternateJoints = EditorGUILayout.Toggle("Alternate Joints", t.alternateJoints)) + //{ + // EditorGUILayout.BeginHorizontal(); + // GUILayout.Space(25); + // t.firstJointAlternated = EditorGUILayout.Toggle("First Joint Alternated", t.firstJointAlternated); + // EditorGUILayout.EndHorizontal(); + //} + + //if (GUI.changed) + // t.OnInitializeMesh(); + } +} \ No newline at end of file diff --git a/Assets/QuickRopes 2/CoreScripts/Editor/QuickRope2PrefabEditor.cs.meta b/Assets/QuickRopes 2/CoreScripts/Editor/QuickRope2PrefabEditor.cs.meta new file mode 100644 index 0000000..e9ec459 --- /dev/null +++ b/Assets/QuickRopes 2/CoreScripts/Editor/QuickRope2PrefabEditor.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 29ce7380d5dcd4a488e9724179ff094d +labels: +- editor +- physics +- chain +- string +- cable +- reverie +- interactive +- quickropes +- gameplay +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/QuickRopes 2/CoreScripts/QuickRope2.cs b/Assets/QuickRopes 2/CoreScripts/QuickRope2.cs new file mode 100644 index 0000000..8812c9f --- /dev/null +++ b/Assets/QuickRopes 2/CoreScripts/QuickRope2.cs @@ -0,0 +1,1002 @@ +using UnityEngine; +using System.Collections; +using System.Collections.Generic; + +public enum BasicRopeTypes +{ + NONE, + Line, + Prefab, + Mesh, + Cloth +} + +public enum RopeConstraint +{ + NONE, + X_Y, + Y_Z, + Z_X +} + +public enum RopeColliderType +{ + DEFAULT, + Sphere, + Capsule +} + +public enum RopeAttachmentJointType +{ + Fixed, + Hinge + //Character +} + +[System.Serializable] +public class RopeAttachedObject +{ + public GameObject go; + public RopeAttachmentJointType jointType = RopeAttachmentJointType.Fixed; + public int jointIndex = 0; + public Vector3 hingeAxis = Vector3.forward; + public Joint jointRef = null; +} + + +[System.Serializable] +public class QuickRope2 : MonoBehaviour +{ + #region BASIC ROPE VARIABLES + public const float PRECISION = 0.0001f; + public const int MAX_JOINT_COUNT = 500; + public const float MAX_JOINT_SPACING = 50; + public const float MIN_JOINT_SPACING = 0.1f; + + public GameObject ropeEnd = null; + public LayerMask layer; + public float jointSpacing = 1f; + public bool showJoints = false; + + public event System.Action OnInitializeMesh; + + [HideInInspector()] + [SerializeField] + private GameObject jointPrefab = null; + public GameObject JointPrefab { get { return jointPrefab; } set { jointPrefab = value; } } + + [HideInInspector()] + [SerializeField] + private float jointScale = 1; + public float JointScale { get { return jointScale; } set { jointScale = value; } } + + [HideInInspector()] + [SerializeField] + private bool alternateJoints = false; + public bool AlternateJoints { get { return alternateJoints; } set { alternateJoints = value; } } + + [HideInInspector()] + [SerializeField] + private bool firstJointAlternated = false; + public bool FirstJointAlternated { get { return firstJointAlternated; } set { firstJointAlternated = value; } } + + [HideInInspector()] + [SerializeField] + private List controlPoints = new List(); + public List ControlPoints { get { return controlPoints; } set { controlPoints = value; } } + + [HideInInspector()] + [SerializeField] + private List splinePoints = new List(); + public List SplinePoints { get { return splinePoints; } } + + [HideInInspector()] + [SerializeField] + public List Joints = new List(); + + [HideInInspector()] + [SerializeField] + private List calculatedPositions = new List(); + + [HideInInspector()] + [SerializeField] + private Quaternion[] calculatedRotations; + + [HideInInspector()] + [SerializeField] + public List attachedObjects = new List(); + + public Vector3[] JointPositions + { + get + { + if (Joints.Count == 0) + return new Vector3[] { Vector3.zero }; + + Vector3[] pos = new Vector3[Joints.Count]; + for (int i = 0; i < pos.Length; i++) + { + pos[i] = Joints[i].transform.position; + } + return pos; + } + } + public Quaternion[] JointRotations + { + get + { + Quaternion[] rots = new Quaternion[Joints.Count]; + rots[0] = Quaternion.LookRotation(Joints[0].transform.position - Joints[1].transform.position); + for (int i = 1; i < rots.Length; i++) + { + rots[i] = Quaternion.LookRotation(Joints[i-1].transform.position - Joints[i].transform.position); + } + return rots; + } + } + private int prevJointcount = 0; + private float ropeLength = 0; + public float RopeLength + { + get + { + if (prevJointcount != Joints.Count) + { + ropeLength = 0; + for (int i = 1; i < Joints.Count; i++) + { + ropeLength += Vector3.Distance(Joints[i - 1].transform.position, Joints[i].transform.position); + } + + prevJointcount = Joints.Count; + } + + return ropeLength; + } + } + + private bool freeFallMode = false; + public bool FreeFallMode + { + get { return freeFallMode; } + set + { + freeFallMode = value; + + if (value) + { + Joints[0].GetComponent().connectedBody = null; + Joints[1].transform.parent = Joints[0].transform; + //Joints[1].rigidbody.isKinematic = true; + } + else + { + Joints[0].GetComponent().connectedBody = Joints[1].GetComponent(); + Joints[1].transform.parent = null; + //Joints[1].rigidbody.isKinematic = false; + } + } + } + + private Vector3 pastUp = Vector3.zero; + private Vector3 pRopeEndPos = Vector3.zero; + private bool initialized = false; + #endregion + + #region PHYSICS VARIABLES + public bool enablePhysics = false; + public RopeColliderType colliderType = RopeColliderType.DEFAULT; + public PhysicMaterial physicsMaterial = null; + public float colliderRadius = 0.25f; + + public RopeConstraint constraint = RopeConstraint.NONE; + + public float mass = 1; + public float drag = 0.2f; + public float angDrag = 0.05f; + public bool useGravity = true; + + public float LowAngXLimit = -60; + public float HighAngXLimit = 60; + public float LTLBounce = 0; + public float LTLSpring = 0; + public float LTLDamper = 0; + + public float AngYLimit = 35; + public float AngZLimit = 35; + public float S1LBounce = 0; + public float S1LSpring = 0; + public float S1LDamper = 0; + + public float breakForce = Mathf.Infinity; + public float breakTorque = Mathf.Infinity; + + public int solverOverride = -1; + #endregion + + #region CONTROLLER VARIABLES + private float distBetweenJoints = 0; + private float currentVelocity = 0; + + public bool enableRopeController = false; + public KeyCode extendRopeKey = KeyCode.DownArrow; + public KeyCode retractRopeKey = KeyCode.UpArrow; + public float acceleration = 10; + public float dampening = 0.96f; + public float sleepVelocity = 0.5f; + public float minRopeLength = 5; + public float maxRopeLength = 25; + public float maxVelocity = 5; + #endregion + + [HideInInspector] + public int EDITOR_TAB_SELECTED = 0; + [HideInInspector] + public static float EDITOR_GUI_SCALE = 0.5f; + [HideInInspector] + public bool EDITOR_SHOW_RIGIDBODY = true; + [HideInInspector] + public bool EDITOR_SHOW_JOINTSETTINGS = false; + [HideInInspector] + public bool EDITOR_SHOW_COLLIDERSETTINGS = false; + + void OnDrawGizmosSelected() + { + Gizmos.color = new Color(0.5f, 0.5f, 0.5f, 0.5f); + for (int i = 2; i < splinePoints.Count - 1; i++) + Gizmos.DrawLine(splinePoints[i], splinePoints[i - 1]); + + for (int i = 1; i < controlPoints.Count; i++) + Gizmos.DrawLine(controlPoints[i], controlPoints[i - 1]); + + if (enablePhysics && colliderType != RopeColliderType.DEFAULT) + { + Gizmos.color = new Color(0.1f, 0.7f, 0.4f); + foreach (GameObject go in Joints) + { + Gizmos.DrawWireSphere(go.transform.position, colliderRadius); + } + } + } + void OnDrawGizmos() + { + if (Application.isPlaying) + return; + + if (splinePoints.Count > 3) + { + Gizmos.color = Color.black; + Vector3 prevPt = CalcPositionAtTime(0); + + for (int i = 1; i <= 100; i++) + { + float pm = (float)i / (float)100; + Vector3 currPt = CalcPositionAtTime(pm); + Gizmos.DrawLine(currPt, prevPt); + prevPt = currPt; + } + + Gizmos.color = Color.white; + } + + if (ropeEnd && QuickRope2Helper.HasMoved(ref pRopeEndPos, ropeEnd.transform.position)) + { + ApplyRopeSettings(); + } + } + + void OnDestroy() + { + if (enablePhysics && Application.isPlaying) + { + foreach (RopeAttachedObject ao in attachedObjects) + Destroy(ao.jointRef); + } + + ClearJointObjects(); + } + void Start() + { + if (ropeEnd == null) + return; + + if (!initialized) + { + ApplyRopeSettings(); + AttachObjects(); + } + distBetweenJoints = Vector3.Distance(Joints[0].transform.position, Joints[1].transform.position); + } + void Update() + { + if (!enablePhysics) + return; + + if (freeFallMode) + { + UpdateFreeFall(); + return; + } + + if (!enableRopeController) + return; + + bool applyingForces = false; + if (Input.GetKey(extendRopeKey)) + { + currentVelocity += acceleration * Time.deltaTime; + applyingForces = true; + } + if (Input.GetKey(retractRopeKey)) + { + currentVelocity -= acceleration * Time.deltaTime; + applyingForces = true; + } + + currentVelocity = Mathf.Clamp(currentVelocity, -maxVelocity, maxVelocity); + + if ((RopeLength < minRopeLength && currentVelocity < 0) || (RopeLength > maxRopeLength && currentVelocity > 0)) + { + currentVelocity = 0; + } + + if (currentVelocity > 0) + ExtendRope(currentVelocity); + + if (currentVelocity < 0) + RetractRope(currentVelocity); + + if (!applyingForces) + { + currentVelocity *= dampening; + if (currentVelocity != 0 && Mathf.Abs(currentVelocity) < sleepVelocity) + { + currentVelocity = 0; + //Joints[0].GetComponent().connectedBody = Joints[1].rigidbody; + //Joints[1].transform.parent = null; + //Joints[1].rigidbody.isKinematic = false; + } + } + } + void RetractRope(float velocity) + { + Joints[1].transform.parent = Joints[0].transform; + Joints[0].GetComponent().connectedBody = null; + Joints[1].GetComponent().isKinematic = true; + Joints[1].transform.position = Vector3.MoveTowards(Joints[1].transform.position, Joints[0].transform.position, Time.deltaTime * velocity * -1); + + if (Vector3.Distance(Joints[1].transform.position, Joints[0].transform.position) <= 0.001f) + { + GameObject go = Joints[1]; + Joints.RemoveAt(1); + Joints.TrimExcess(); + Destroy(go); + //Joints[1].transform.parent = Joints[0].transform; + //Joints[1].rigidbody.isKinematic = true; + } + + Joints[0].GetComponent().connectedBody = Joints[1].GetComponent(); + Joints[1].GetComponent().isKinematic = false; + } + void ExtendRope(float velocity) + { + Joints[0].GetComponent().connectedBody = null; + Joints[1].GetComponent().isKinematic = true; + //Joints[1].transform.position = Vector3.MoveTowards(Joints[1].transform.position, Joints[1].transform.position + (Joints[1].transform.position - Joints[0].transform.position).normalized, Time.deltaTime * velocity); + Joints[1].transform.position = Vector3.MoveTowards(Joints[1].transform.position, Joints[1].transform.position - (Joints[0].transform.position - Joints[2].transform.position).normalized , Time.deltaTime * velocity); + + //Debug.DrawRay(Joints[1].transform.position, (Joints[0].transform.position - Joints[1].transform.position).normalized * 10); + //Joints[1].transform.LookAt(Joints[0].transform.position); + + if (Vector3.Distance(Joints[1].transform.position, Joints[0].transform.position) > (distBetweenJoints*1.5f)) + { + GameObject go; + if (JointPrefab != null) + { + go = (GameObject)Instantiate(JointPrefab, Joints[1].transform.position - ((Joints[1].transform.position - Joints[0].transform.position).normalized * distBetweenJoints), Quaternion.LookRotation(Joints[0].transform.position - Joints[1].transform.position));// Quaternion.LookRotation(Joints[0].transform.position - Joints[1].transform.position)); + float ang = (alternateJoints) ? ((firstJointAlternated) ? ((Joints.Count % 2 == 0) ? 90 : 0) : ((Joints.Count % 2 == 0) ? 0 : 90)) : 0; + go.transform.Rotate(0, 0, ang); + go.transform.localScale = Vector3.one * jointScale; + } + else + { + go = new GameObject("Jnt_" + Joints.Count); + go.transform.position = Joints[1].transform.position - ((Joints[1].transform.position - Joints[0].transform.position).normalized * distBetweenJoints); + go.transform.rotation = Quaternion.LookRotation(Joints[0].transform.position - Joints[1].transform.position); + float ang = (alternateJoints) ? ((firstJointAlternated) ? ((Joints.Count % 2 == 0) ? 0 : 90) : ((Joints.Count % 2 == 0) ? 90 : 0)) : 0; + go.transform.Rotate(0, 0, ang); + } + + go.layer = gameObject.layer; + go.tag = gameObject.tag; + + if (!showJoints) + go.hideFlags = HideFlags.HideInHierarchy | HideFlags.NotEditable; + + if (go.GetComponent()) + go.GetComponent().enabled = false; + + AddConfigJoint(go).connectedBody = Joints[1].GetComponent(); + + switch (colliderType) + { + case RopeColliderType.Sphere: + SphereCollider sc; + sc = go.AddComponent(); + sc.radius = colliderRadius; + sc.center = Vector3.zero; + + if (physicsMaterial != null) + sc.sharedMaterial = physicsMaterial; + break; + case RopeColliderType.Capsule: + CapsuleCollider cc; + float len = Vector3.Distance(go.transform.position, Joints[1].transform.position); + + cc = go.AddComponent(); + cc.radius = colliderRadius; + cc.center = new Vector3(0, 0, len / 2f); + cc.direction = 2; + cc.height = len + (cc.radius + cc.radius); + + if (physicsMaterial != null) + cc.sharedMaterial = physicsMaterial; + break; + } + + Joints[1].GetComponent().isKinematic = false; + Joints.Insert(1, go); + Joints.TrimExcess(); + } + + Joints[1].GetComponent().isKinematic = false; + Joints[0].GetComponent().connectedBody = Joints[1].GetComponent(); + } + void UpdateFreeFall() + { + //Joints[1].transform.position = Vector3.MoveTowards(Joints[1].transform.position, Joints[1].transform.position + (Joints[1].transform.position - Joints[0].transform.position).normalized, Time.deltaTime * velocity); + if (RopeLength > maxRopeLength) + { + FreeFallMode = false; + return; + } + + if (Vector3.Distance(Joints[1].transform.position, Joints[0].transform.position) > distBetweenJoints) + { + GameObject go; + if (JointPrefab != null) + { + go = (GameObject)Instantiate(JointPrefab, Joints[1].transform.position - ((Joints[1].transform.position - Joints[0].transform.position).normalized * distBetweenJoints), Quaternion.identity);// Quaternion.LookRotation(Joints[0].transform.position - Joints[1].transform.position)); + go.transform.LookAt(Joints[0].transform.position); + //go.transform.Rotate(0, 0, Joints[1].transform.eulerAngles.z + 90); + float ang = (alternateJoints) ? ((firstJointAlternated) ? ((Joints.Count % 2 == 0) ? 90 : 0) : ((Joints.Count % 2 == 0) ? 0 : 90)) : 0; + go.transform.Rotate(0, 0, ang); + go.transform.localScale = Vector3.one * jointScale; + } + else + { + go = new GameObject("Jnt_NULL"); + go.transform.position = Joints[1].transform.position - ((Joints[1].transform.position - Joints[0].transform.position).normalized * distBetweenJoints); + go.transform.rotation = Quaternion.identity; + } + + go.layer = gameObject.layer; + go.tag = gameObject.tag; + + if (!showJoints) + go.hideFlags = HideFlags.HideInHierarchy | HideFlags.NotEditable; + + if (go.GetComponent()) + go.GetComponent().enabled = false; + + AddConfigJoint(go).connectedBody = Joints[1].GetComponent(); + Joints[1].transform.parent = null; + //Joints[1].rigidbody.isKinematic = false; + Joints.Insert(1, go); + Joints.TrimExcess(); + Joints[1].transform.parent = Joints[0].transform; + //Joints[1].rigidbody.isKinematic = true; + } + } + + public void GenerateJointObjects() + { + ClearJointObjects(); + + Joints.Add(gameObject); + + for (int i = 1; i < SplinePoints.Count - 1; i++) + { + GameObject go; + if (JointPrefab != null) + { + go = (GameObject)Instantiate(JointPrefab, SplinePoints[i], calculatedRotations[i]); + + if (alternateJoints) + { + int comparitor = (firstJointAlternated) ? 1 : 0; + go.transform.Rotate(0, 0, (i % 2 == comparitor) ? 90 : 0); + } + + go.transform.localScale = jointPrefab.transform.localScale * jointScale; + } + else + { + go = new GameObject("Jnt_" + i.ToString()); + go.transform.position = SplinePoints[i]; + go.transform.rotation = calculatedRotations[i]; + } + + go.layer = gameObject.layer; + go.tag = gameObject.tag; + + if (!Application.isPlaying) + go.transform.parent = transform; + + if (!showJoints) + go.hideFlags = HideFlags.HideInHierarchy | HideFlags.NotEditable; + + if (go.GetComponent()) + go.GetComponent().enabled = false; + + Joints.Add(go); + } + + Joints.Add(ropeEnd); + } + public void ClearJointObjects() + { + for(int i = 0; i < Joints.Count; i++) + { + if (Joints[i].GetInstanceID() == gameObject.GetInstanceID() || Joints[i].GetInstanceID() == ropeEnd.GetInstanceID()) + continue; + + if (Application.isPlaying) + { + Destroy(Joints[i]); + } + else + { + DestroyImmediate(Joints[i]); + } + } + + Joints.Clear(); + Joints.TrimExcess(); + } + private void PreCalculateRotations() + { + calculatedRotations = new Quaternion[SplinePoints.Count]; + calculatedRotations[0] = Quaternion.LookRotation(SplinePoints[0] - SplinePoints[1]); + for (int i = 1; i < calculatedRotations.Length; i++) + { + calculatedRotations[i] = Quaternion.LookRotation(SplinePoints[i - 1] - SplinePoints[i]); + } + } + public Quaternion[] GetRotations(Vector3[] points) + { + Vector3[] directions = new Vector3[points.Length]; ; + Quaternion[] rotations = new Quaternion[points.Length]; ; + Vector3 forward, up; + + for (int p = 0; p < points.Length - 1; p++) + directions[p] = points[p + 1] - points[p]; + + directions[points.Length - 1] = directions[points.Length - 2]; + + if (pastUp == Vector3.zero) + { + up = directions[0].x == 0 && directions[0].z == 0 ? Vector3.right : Vector3.up; + } + else + { + up = pastUp; + } + + for (int p = 0; p < points.Length; p++) + { + if (p != 0 && p != points.Length - 1) + { + forward = directions[p] + directions[p - 1]; + } + else + { + if (points[0] == points[points.Length - 1]) forward = directions[points.Length - 1] + directions[0]; + else forward = directions[p]; + } + + if (forward == Vector3.zero) + { + rotations[p] = Quaternion.identity; + continue; + } + + forward.Normalize(); + Vector3 right = Vector3.Cross(up, forward); + if (right == Vector3.zero) + right = Vector3.Cross(new Vector3(-0.3f, 0.1f, 0), new Vector3(0, 0, 0.4f)); + + up = Vector3.Cross(forward, right); + + if (p == 0) + pastUp = up; + + if (right != Vector3.zero) + rotations[p].SetLookRotation(-right, up); + } + + return rotations; + } + private Vector3 CalcPositionAtTime(float t) + { + int numSections = calculatedPositions.Count - 3; + int currPt = Mathf.Min(Mathf.FloorToInt(t * (float)numSections), numSections - 1); + float u = t * (float)numSections - (float)currPt; + + Vector3 a = calculatedPositions[currPt]; + Vector3 b = calculatedPositions[currPt + 1]; + Vector3 c = calculatedPositions[currPt + 2]; + Vector3 d = calculatedPositions[currPt + 3]; + + return .5f * ( + (-a + 3f * b - 3f * c + d) * (u * u * u) + + (2f * a - 5f * b + 4f * c - d) * (u * u) + + (-a + c) * u + + 2f * b + ); + } + + #region PHYSICS - Settings + void UpdatePhysics() + { + if (Joints.Count == 0 || !enablePhysics) + return; + + // ====== ADD RIGIDBODIES ========= + for (int r = 0; r < Joints.Count; r++) + { + GameObject go = Joints[r]; + + if (go == null) + return; + + if (go.GetComponent() == null) + go.AddComponent(); + + switch (constraint) + { + case RopeConstraint.NONE: + go.GetComponent().constraints = RigidbodyConstraints.None; + break; + case RopeConstraint.X_Y: + go.GetComponent().constraints = RigidbodyConstraints.FreezeRotationY | RigidbodyConstraints.FreezeRotationX | RigidbodyConstraints.FreezePositionZ; + break; + case RopeConstraint.Y_Z: + go.GetComponent().constraints = RigidbodyConstraints.FreezeRotationY | RigidbodyConstraints.FreezeRotationZ | RigidbodyConstraints.FreezePositionX; + break; + case RopeConstraint.Z_X: + go.GetComponent().constraints = RigidbodyConstraints.FreezeRotationZ | RigidbodyConstraints.FreezeRotationX | RigidbodyConstraints.FreezePositionY; + break; + } + + if (solverOverride != -1 && solverOverride > 1) + go.GetComponent().solverIterationCount = solverOverride; + + go.GetComponent().mass = mass; + go.GetComponent().angularDrag = angDrag; + go.GetComponent().drag = drag; + go.GetComponent().useGravity = useGravity; + } + + if (Application.isPlaying) + { + // ========= ADD CONFIG JOINTS ============ + for (int c = 0; c < Joints.Count - 1; c++) + AddConfigJoint(Joints[c]).connectedBody = Joints[c + 1].GetComponent(); + + // ========= ADD COLLIDERS ============== + if (colliderType != RopeColliderType.DEFAULT) + AddColliders(); + } + } + ConfigurableJoint AddConfigJoint(GameObject joint) + { + if (Application.isPlaying) + Destroy(joint.GetComponent()); + else + DestroyImmediate(joint.GetComponent()); + + if (Application.isPlaying && joint.GetComponent() && colliderType == RopeColliderType.DEFAULT) + joint.GetComponent().enabled = true; + + ConfigurableJoint cj = joint.AddComponent(); + + cj.anchor = Vector3.zero; + cj.xMotion = ConfigurableJointMotion.Locked; + cj.yMotion = ConfigurableJointMotion.Locked; + cj.zMotion = ConfigurableJointMotion.Locked; + + cj.angularXMotion = ConfigurableJointMotion.Limited; + cj.angularYMotion = ConfigurableJointMotion.Limited; + cj.angularZMotion = ConfigurableJointMotion.Limited; + + cj.lowAngularXLimit = new SoftJointLimit() { limit = LowAngXLimit, bounciness = LTLBounce/*, spring = LTLSpring, damper = LTLDamper*/ }; + cj.highAngularXLimit = new SoftJointLimit() { limit = HighAngXLimit, bounciness = LTLBounce/*, spring = LTLSpring, damper = LTLDamper*/ }; + cj.angularYLimit = new SoftJointLimit() { limit = AngYLimit, bounciness = S1LBounce/*, spring = S1LSpring, damper = S1LDamper*/ }; + cj.angularZLimit = new SoftJointLimit() { limit = AngZLimit, bounciness = S1LBounce/*, spring = S1LSpring, damper = S1LDamper*/ }; + + + if (!enableRopeController) + { + cj.breakForce = breakForce; + cj.breakTorque = breakTorque; + } + + return cj; + } + void AddColliders() + { + if (!Application.isPlaying) + return; + + switch (colliderType) + { + case RopeColliderType.Sphere: + SphereCollider sc; + for (int i = 1; i < Joints.Count - 1; i++) + { + sc = Joints[i].AddComponent(); + sc.radius = colliderRadius; + sc.center = Vector3.zero; + + if (physicsMaterial != null) + sc.sharedMaterial = physicsMaterial; + } + break; + case RopeColliderType.Capsule: + CapsuleCollider cc; + for (int i = 1; i < Joints.Count; i++) + { + float len = Vector3.Distance(Joints[i].transform.position, Joints[i - 1].transform.position); + + if (len < colliderRadius) + continue; + + cc = Joints[i].AddComponent(); + cc.radius = colliderRadius; + cc.center = new Vector3(0, 0, len / 2f); + cc.direction = 2; + cc.height = len + (cc.radius + cc.radius); + + if (physicsMaterial != null) + cc.sharedMaterial = physicsMaterial; + } + break; + } + } + #endregion + + void AttachObjects() + { + if (enablePhysics && Application.isPlaying) + { + foreach (RopeAttachedObject ao in attachedObjects) + { + if (ao.go == null) + continue; + + if (ao.jointIndex > Joints.Count - 1) + ao.jointIndex = Joints.Count - 1; + + switch (ao.jointType) + { + case RopeAttachmentJointType.Fixed: + ao.jointRef = Joints[ao.jointIndex].AddComponent(); + ao.jointRef.connectedBody = ao.go.GetComponent(); + break; + case RopeAttachmentJointType.Hinge: + ao.jointRef = ao.go.AddComponent();//ao.jointRef = Joints[ao.jointIndex].AddComponent(); + (ao.jointRef as HingeJoint).axis = ao.hingeAxis; + ao.jointRef.connectedBody = Joints[ao.jointIndex].GetComponent();//ao.jointRef.connectedBody = ao.go.GetComponent(); + break; + } + } + } + } + + public void ApplyRopeSettings() + { + if (ropeEnd == null) + return; + + // ============== Setup For Spline Point Generation + calculatedPositions.Clear(); calculatedPositions.TrimExcess(); + calculatedPositions.Add(transform.position); + calculatedPositions.AddRange(controlPoints); + calculatedPositions.Add(ropeEnd.transform.position); + calculatedPositions.Insert(0, transform.position - (calculatedPositions[1] - calculatedPositions[0]).normalized); + calculatedPositions.Add(calculatedPositions[calculatedPositions.Count - 1] + (calculatedPositions[calculatedPositions.Count - 1] - calculatedPositions[calculatedPositions.Count - 2]).normalized); + // ================================================ + + float time = 0f; + Vector3 nsPosOffset = Vector3.zero; + + splinePoints.Clear(); splinePoints.TrimExcess(); + splinePoints.Add(CalcPositionAtTime(time)); + + while (time <= 1f) + { + Vector3 p = CalcPositionAtTime(time); + if (Vector3.Distance(splinePoints[splinePoints.Count - 1], (p + nsPosOffset)) >= jointSpacing) + splinePoints.Add(p); + + time += PRECISION; + } + + splinePoints.Add(CalcPositionAtTime(1)); + + PreCalculateRotations(); + + transform.rotation = calculatedRotations[0]; + ropeEnd.transform.rotation = calculatedRotations[calculatedRotations.Length - 1]; + + if (gameObject.GetComponent() == null && gameObject.GetComponent() == null) + GenerateJointObjects(); + + JointPrefab = null; + if (OnInitializeMesh != null) + OnInitializeMesh(); + + if (gameObject.GetComponent() == null) + UpdatePhysics(); + + initialized = true; + } + public void RebuildMesh() + { + if (!initialized) + return; + + if (OnInitializeMesh != null) + OnInitializeMesh(); + } + + public void AttachObject(GameObject obj, int jointIndex, RopeAttachmentJointType jointType, Vector3 hingeAxis, bool centerOnIndex) + { + if (gameObject.GetComponent()) + { + Debug.LogError("You must use the \"Cloth\" component to attach objects when using the Cloth mesh type."); + return; + } + + RopeAttachedObject rao = new RopeAttachedObject(); + rao.go = obj; + rao.jointIndex = jointIndex; + rao.jointType = jointType; + rao.hingeAxis = hingeAxis; + + if (centerOnIndex) + rao.go.transform.position = Joints[rao.jointIndex].transform.position; + + attachedObjects.Add(rao); + + if (Application.isPlaying) + { + if (rao.go == null) + return; + + switch (rao.jointType) + { + case RopeAttachmentJointType.Fixed: + rao.jointRef = Joints[rao.jointIndex].AddComponent(); + rao.jointRef.connectedBody = rao.go.GetComponent(); + break; + case RopeAttachmentJointType.Hinge: + //rao.jointRef = Joints[rao.jointIndex].AddComponent(); + //(rao.jointRef as HingeJoint).axis = rao.hingeAxis; + //rao.jointRef.connectedBody = rao.go.GetComponent(); + + rao.jointRef = rao.go.AddComponent();//ao.jointRef = Joints[ao.jointIndex].AddComponent(); + (rao.jointRef as HingeJoint).axis = rao.hingeAxis; + rao.jointRef.connectedBody = Joints[rao.jointIndex].GetComponent();//ao.jointRef.connectedBody = ao.go.GetComponent(); + + break; + } + } + } + public void AttachObject(GameObject obj, int jointIndex, RopeAttachmentJointType jointType, bool centerOnIndex) + { + AttachObject(obj, jointIndex, jointType, Vector3.forward, centerOnIndex); + } + public void AttachObject(GameObject obj, int jointIndex, bool centerOnIndex) + { + AttachObject(obj, jointIndex, RopeAttachmentJointType.Fixed, centerOnIndex); + } + public void DetachObject(GameObject obj) + { + foreach (RopeAttachedObject ao in attachedObjects) + { + if (ao.go.GetInstanceID() == obj.GetInstanceID()) + { + if (Application.isPlaying) + Destroy(ao.jointRef); + else + DestroyImmediate(ao.jointRef); + + attachedObjects.Remove(ao); + attachedObjects.TrimExcess(); + return; + } + } + } + + public static QuickRope2 Create(GameObject pointA, GameObject pointB, List curvePoints, BasicRopeTypes ropeType) + { + QuickRope2 qr = pointA.AddComponent(); + qr.ropeEnd = pointB; + + switch (ropeType) + { + case BasicRopeTypes.NONE: + break; + case BasicRopeTypes.Line: + qr.gameObject.AddComponent(); + break; + case BasicRopeTypes.Prefab: + qr.gameObject.AddComponent(); + break; + case BasicRopeTypes.Mesh: + qr.gameObject.AddComponent(); + break; + case BasicRopeTypes.Cloth: + qr.gameObject.AddComponent(); + break; + } + + qr.ApplyRopeSettings(); + + return qr; + } + public static QuickRope2 Create(Vector3 pointA, Vector3 pointB, List curvePoints, BasicRopeTypes ropeType) + { + GameObject ob1 = new GameObject("Rope"); + GameObject ob2 = new GameObject("Rope_End"); + + ob1.transform.position = pointA; + ob2.transform.position = pointB; + + return Create(ob1, ob2, curvePoints, ropeType); + } + public static QuickRope2 Create(GameObject pointA, Vector3 pointB, List curvePoints, BasicRopeTypes ropeType) + { + GameObject ob1 = new GameObject("Rope_End"); + + ob1.transform.position = pointB; + + return Create(pointA, ob1, curvePoints, ropeType); + } + public static QuickRope2 Create(Vector3 pointA, GameObject pointB, List curvePoints, BasicRopeTypes ropeType) + { + GameObject ob1 = new GameObject("Rope"); + + ob1.transform.position = pointA; + + return Create(ob1, pointB, curvePoints, ropeType); + } + public static QuickRope2 Create(GameObject pointA, GameObject pointB, BasicRopeTypes ropeType) + { + return Create(pointA, pointB, null, ropeType); + } + public static QuickRope2 Create(Vector3 pointA, GameObject pointB, BasicRopeTypes ropeType) + { + return Create(pointA, pointB, null, ropeType); + } + public static QuickRope2 Create(GameObject pointA, Vector3 pointB, BasicRopeTypes ropeType) + { + return Create(pointA, pointB, null, ropeType); + } + public static QuickRope2 Create(Vector3 pointA, Vector3 pointB, BasicRopeTypes ropeType) + { + return Create(pointA, pointB, null, ropeType); + } +} diff --git a/Assets/QuickRopes 2/CoreScripts/QuickRope2.cs.meta b/Assets/QuickRopes 2/CoreScripts/QuickRope2.cs.meta new file mode 100644 index 0000000..63c2652 --- /dev/null +++ b/Assets/QuickRopes 2/CoreScripts/QuickRope2.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: ae2e5f8c61e368e4aacf8d5b7e443c87 +labels: +- editor +- physics +- chain +- string +- cable +- reverie +- interactive +- quickropes +- gameplay +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/QuickRopes 2/CoreScripts/QuickRope2Cloth.cs b/Assets/QuickRopes 2/CoreScripts/QuickRope2Cloth.cs new file mode 100644 index 0000000..f54a5cd --- /dev/null +++ b/Assets/QuickRopes 2/CoreScripts/QuickRope2Cloth.cs @@ -0,0 +1,77 @@ +using UnityEngine; +using System.Collections; + +[RequireComponent(typeof(QuickRope2))] +[ExecuteInEditMode()] +public class QuickRope2Cloth : MonoBehaviour +{ + public int maxRadius = 5; + public AnimationCurve curve = new AnimationCurve(new Keyframe(0, .3f), new Keyframe(1, .3f)); + public int crossSegments = 6; + + [SerializeField] + private RopeTubeRenderer tube; + private QuickRope2 rope; + private Cloth mFilter; + private SkinnedMeshRenderer mRender; + + void OnEnable() + { + rope = GetComponent(); + rope.OnInitializeMesh += OnInitializeMesh; + } + + void OnDisable() + { + rope.OnInitializeMesh -= OnInitializeMesh; + if (rope != null) + rope.ClearJointObjects(); + } + + void OnDestroy() + { + rope.OnInitializeMesh -= OnInitializeMesh; + if (rope != null) + rope.ClearJointObjects(); + } + + public void OnInitializeMesh() + { + rope.GenerateJointObjects(); + + if (tube == null) + tube = new RopeTubeRenderer(gameObject, true); + + mRender = gameObject.GetComponent(); + if (mRender == null) + mRender = gameObject.AddComponent(); + + mFilter = gameObject.GetComponent(); + if (mFilter == null) + mFilter = gameObject.AddComponent(); + + GenerateMesh(); + + //if (useAutoTextureTiling) + // gameObject.GetComponent().sharedMaterial.mainTextureScale = new Vector2(rope.Joints.Count / 2f, 1); + + if (gameObject.GetComponent().sharedMaterial == null) + gameObject.GetComponent().sharedMaterial = (Material)Resources.Load("Materials/Rope", typeof(Material)); + } + + public void GenerateMesh() + { + tube.SetPointsAndRotations(rope.JointPositions, rope.GetRotations(rope.JointPositions)); + tube.SetEdgeCount(crossSegments); + + float[] rads = new float[rope.JointPositions.Length]; + for (int i = 0; i < rads.Length; i++) + { + rads[i] = curve.Evaluate(i * (1f / rads.Length)); + } + tube.SetRadiuses(rads); + + tube.Update(); + mRender.sharedMesh = tube.mesh; + } +} diff --git a/Assets/QuickRopes 2/CoreScripts/QuickRope2Cloth.cs.meta b/Assets/QuickRopes 2/CoreScripts/QuickRope2Cloth.cs.meta new file mode 100644 index 0000000..91d9497 --- /dev/null +++ b/Assets/QuickRopes 2/CoreScripts/QuickRope2Cloth.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 805db666378c9a9438cabc9bb32ce116 +labels: +- editor +- physics +- chain +- string +- cable +- reverie +- interactive +- quickropes +- gameplay +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/QuickRopes 2/CoreScripts/QuickRope2Helper.cs b/Assets/QuickRopes 2/CoreScripts/QuickRope2Helper.cs new file mode 100644 index 0000000..9516edc --- /dev/null +++ b/Assets/QuickRopes 2/CoreScripts/QuickRope2Helper.cs @@ -0,0 +1,62 @@ +using UnityEngine; +using System.Collections; +using System.Collections.Generic; + +public class QuickRope2Helper +{ + public static bool HasMoved(ref Vector3 prevPoint, Vector3 curPoint) + { + bool r = Vector3.Distance(curPoint, prevPoint) >= 0.01f; + + if (r) prevPoint = curPoint; + + return r; + } +} + +[System.Serializable] +public class QuickRopeSpline +{ + public List Points; + + public Vector3 Interpolate(float t) + { + if (Points.Count < 4) + return Vector3.zero; + + int numSections = Points.Count - 3; + int currPt = Mathf.Min(Mathf.FloorToInt(t * (float)numSections), numSections - 1); + float u = t * (float)numSections - (float)currPt; + + Vector3 a = Points[currPt]; + Vector3 b = Points[currPt + 1]; + Vector3 c = Points[currPt + 2]; + Vector3 d = Points[currPt + 3]; + + return .5f * ( + (-a + 3f * b - 3f * c + d) * (u * u * u) + + (2f * a - 5f * b + 4f * c - d) * (u * u) + + (-a + c) * u + + 2f * b + ); + } + + public void DrawGizmo(float t, int precision, Color splineColor) + { + if (Points.Count < 3) + return; + + Gizmos.color = splineColor; + Vector3 prevPt = Interpolate(0); + + for (int i = 1; i <= 100; i++) + { + float pm = (float)i / (float)100; + Vector3 currPt = Interpolate(pm); + Gizmos.DrawLine(currPt, prevPt); + prevPt = currPt; + } + + Gizmos.color = Color.white; + } +} \ No newline at end of file diff --git a/Assets/QuickRopes 2/CoreScripts/QuickRope2Helper.cs.meta b/Assets/QuickRopes 2/CoreScripts/QuickRope2Helper.cs.meta new file mode 100644 index 0000000..92a0068 --- /dev/null +++ b/Assets/QuickRopes 2/CoreScripts/QuickRope2Helper.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: cbd90374c07cc4e46b3a75a1c140345b +labels: +- editor +- physics +- chain +- string +- cable +- reverie +- interactive +- quickropes +- gameplay +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/QuickRopes 2/CoreScripts/QuickRope2Line.cs b/Assets/QuickRopes 2/CoreScripts/QuickRope2Line.cs new file mode 100644 index 0000000..0427be0 --- /dev/null +++ b/Assets/QuickRopes 2/CoreScripts/QuickRope2Line.cs @@ -0,0 +1,70 @@ +using UnityEngine; +using System.Collections; +using System.Collections.Generic; + +[System.Serializable] +[RequireComponent(typeof(QuickRope2))] +[ExecuteInEditMode()] +public class QuickRope2Line : MonoBehaviour +{ + private QuickRope2 rope; + private LineRenderer line; + public bool useAutoTextureTiling = true; + + void OnEnable() + { + rope = GetComponent(); + + if (gameObject.GetComponent() == null) + line = gameObject.AddComponent(); + else + line = gameObject.GetComponent(); + + if (line.sharedMaterial == null) + line.sharedMaterial = (Material)Resources.Load("Materials/RopeLineMaterial", typeof(Material)); + + rope.OnInitializeMesh += OnInitializeMesh; + } + + void OnDisable() + { + rope.OnInitializeMesh -= OnInitializeMesh; + if (rope != null) + rope.ClearJointObjects(); + } + + void OnDestroy() + { + rope.OnInitializeMesh -= OnInitializeMesh; + if (rope != null) + rope.ClearJointObjects(); + } + + public void OnInitializeMesh() + { + if (rope == null) + return; + + rope.GenerateJointObjects(); + Update(); + + if (useAutoTextureTiling) + gameObject.GetComponent().sharedMaterial.mainTextureScale = new Vector2(rope.Joints.Count / 2f, 1); + } + + void Update() + { + if (line == null) + return; + + if (useAutoTextureTiling && Application.isPlaying) + line.material.mainTextureScale = new Vector2(rope.Joints.Count / 2f, 1); + + int index = 0; + line.SetVertexCount(rope.Joints.Count); + foreach (GameObject go in rope.Joints) + line.SetPosition(index++, go.transform.position); + + //line.SetPosition(index++, rope.ropeEnd.transform.position); + } +} diff --git a/Assets/QuickRopes 2/CoreScripts/QuickRope2Line.cs.meta b/Assets/QuickRopes 2/CoreScripts/QuickRope2Line.cs.meta new file mode 100644 index 0000000..b204fdd --- /dev/null +++ b/Assets/QuickRopes 2/CoreScripts/QuickRope2Line.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 7f6c025d5d759cd44b0b01bda0cfbeae +labels: +- editor +- physics +- chain +- string +- cable +- reverie +- interactive +- quickropes +- gameplay +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/QuickRopes 2/CoreScripts/QuickRope2Mesh.cs b/Assets/QuickRopes 2/CoreScripts/QuickRope2Mesh.cs new file mode 100644 index 0000000..887987e --- /dev/null +++ b/Assets/QuickRopes 2/CoreScripts/QuickRope2Mesh.cs @@ -0,0 +1,92 @@ +using UnityEngine; +using System.Collections; +using System.Collections.Generic; + +[System.Serializable] +[RequireComponent(typeof(QuickRope2))] +[ExecuteInEditMode()] +public class QuickRope2Mesh : MonoBehaviour +{ + public bool meshStatic = false; + public int maxRadius = 5; + public float textureTiling = 1; + [SerializeField] + public AnimationCurve curve = new AnimationCurve(new Keyframe(0, .3f), new Keyframe(1, .3f)); + public Color[] grad; + public int crossSegments = 6; + + [SerializeField] + public RopeTubeRenderer tube; + [SerializeField] + private QuickRope2 rope; + [SerializeField] + private MeshFilter mFilter; + + void OnEnable() + { + rope = GetComponent(); + rope.OnInitializeMesh += OnInitializeMesh; + } + + void OnDisable() + { + rope.OnInitializeMesh -= OnInitializeMesh; + if (rope != null) + rope.ClearJointObjects(); + } + + void OnDestroy() + { + rope.OnInitializeMesh -= OnInitializeMesh; + if (rope != null) + rope.ClearJointObjects(); + } + + public void OnInitializeMesh() + { + //rope.GenerateJointObjects(); + + if (tube == null) + tube = new RopeTubeRenderer(gameObject, false); + + tube.calculateTangents = true; + + UpdateMesh(); + } + + public void UpdateMesh() + { + tube.SetPointsAndRotations(rope.JointPositions, rope.GetRotations(rope.JointPositions)); + tube.SetEdgeCount(crossSegments); + + float[] rads = new float[rope.JointPositions.Length]; + for (int i = 0; i < rads.Length; i++) + { + rads[i] = curve.Evaluate(i * (1f / rads.Length)); + } + + tube.SetRadiuses(rads); + tube.Update(); + + gameObject.GetComponent().sharedMaterial.mainTextureScale = new Vector2(rope.Joints.Count * + textureTiling, 1); + } + + void Update() + { + if (meshStatic || !Application.isPlaying) + return; + + float[] rads = new float[rope.JointPositions.Length]; + for (int i = 0; i < rads.Length; i++) + { + rads[i] = curve.Evaluate(i * (1f / rads.Length)); + } + + tube.SetPointsAndRotations(rope.JointPositions, rope.GetRotations(rope.JointPositions)); + tube.SetRadiuses(rads); + tube.Update(); + + gameObject.GetComponent().material.mainTextureScale = new Vector2(rope.Joints.Count * textureTiling, 1); + } +} diff --git a/Assets/QuickRopes 2/CoreScripts/QuickRope2Mesh.cs.meta b/Assets/QuickRopes 2/CoreScripts/QuickRope2Mesh.cs.meta new file mode 100644 index 0000000..9d00f3b --- /dev/null +++ b/Assets/QuickRopes 2/CoreScripts/QuickRope2Mesh.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 9f1764ce3e0882c47a398e50a6122e3c +labels: +- editor +- physics +- chain +- string +- cable +- reverie +- interactive +- quickropes +- gameplay +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/QuickRopes 2/CoreScripts/QuickRope2Prefab.cs b/Assets/QuickRopes 2/CoreScripts/QuickRope2Prefab.cs new file mode 100644 index 0000000..0dc870a --- /dev/null +++ b/Assets/QuickRopes 2/CoreScripts/QuickRope2Prefab.cs @@ -0,0 +1,73 @@ +using UnityEngine; +using System.Collections; +using System.Collections.Generic; + +[RequireComponent(typeof(QuickRope2))] +[ExecuteInEditMode()] +public class QuickRope2Prefab : MonoBehaviour +{ + public GameObject prefab = null; + public float jointScale = 1; + public bool alternateJoints = true; + public bool firstJointAlternated = false; + + private QuickRope2 rope; + + void OnEnable() + { + rope = GetComponent(); + + if (prefab == null) + prefab = (GameObject)Resources.Load("Link", typeof(GameObject)); + + rope.OnInitializeMesh += OnInitializeMesh; + } + + void OnDisable() + { + rope.OnInitializeMesh -= OnInitializeMesh; + if (rope != null) + rope.ClearJointObjects(); + } + + void OnDestroy() + { + rope.OnInitializeMesh -= OnInitializeMesh; + if (rope != null) + rope.ClearJointObjects(); + } + + public void OnInitializeMesh() + { + if (!prefab) + return; + + //rope.FirstJointAlternated = firstJointAlternated; + //rope.AlternateJoints = alternateJoints; + rope.JointPrefab = prefab; + //rope.AlternateJoints = true; + rope.JointScale = jointScale; + rope.GenerateJointObjects(); + } + + /* + public void OnInsertJointAtStart() + { + Vector3 insertPos = rope.Joints[0].transform.position - ((rope.Joints[0].transform.position - rope.Joints[1].transform.position).normalized * rope.jointSpacing); + + GameObject go; + go = (GameObject)Instantiate(prefab, insertPos, rope.Joints[1].transform.rotation * Quaternion.Euler(0, 0, 90)); + go.transform.localScale = Vector3.one * jointScale; + + if (!rope.showJoints) + go.hideFlags = HideFlags.HideInHierarchy | HideFlags.NotEditable; + + if (go.collider) + go.collider.enabled = false; + + rope.Joints.Insert(1, go); + + rope.RebuildPhysics(); + } + */ +} diff --git a/Assets/QuickRopes 2/CoreScripts/QuickRope2Prefab.cs.meta b/Assets/QuickRopes 2/CoreScripts/QuickRope2Prefab.cs.meta new file mode 100644 index 0000000..442dce5 --- /dev/null +++ b/Assets/QuickRopes 2/CoreScripts/QuickRope2Prefab.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 83d36c9afb65c0646946a2815b5ed00d +labels: +- editor +- physics +- chain +- string +- cable +- reverie +- interactive +- quickropes +- gameplay +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/QuickRopes 2/CoreScripts/Resources.meta b/Assets/QuickRopes 2/CoreScripts/Resources.meta new file mode 100644 index 0000000..4201630 --- /dev/null +++ b/Assets/QuickRopes 2/CoreScripts/Resources.meta @@ -0,0 +1,5 @@ +fileFormatVersion: 2 +guid: 0965c7aa3122d4348a93f0a079cc0a60 +folderAsset: yes +DefaultImporter: + userData: diff --git a/Assets/QuickRopes 2/CoreScripts/Resources/Link.prefab b/Assets/QuickRopes 2/CoreScripts/Resources/Link.prefab new file mode 100644 index 0000000..d1a392e --- /dev/null +++ b/Assets/QuickRopes 2/CoreScripts/Resources/Link.prefab @@ -0,0 +1,83 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &100000 +GameObject: + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + serializedVersion: 4 + m_Component: + - 4: {fileID: 400000} + - 33: {fileID: 3300000} + - 23: {fileID: 2300000} + - 65: {fileID: 6500000} + m_Layer: 0 + m_Name: Link + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &400000 +Transform: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 100000} + m_LocalRotation: {x: 0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: -0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} +--- !u!23 &2300000 +Renderer: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 100000} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_LightmapIndex: 255 + m_LightmapTilingOffset: {x: 1, y: 1, z: 0, w: 0} + m_Materials: + - {fileID: 2100000, guid: 75e20fdf21ee4cd4bbbff5787612aa0f, type: 2} + m_SubsetIndices: + m_StaticBatchRoot: {fileID: 0} + m_UseLightProbes: 0 + m_LightProbeAnchor: {fileID: 0} + m_ScaleInLightmap: 1 + m_SortingLayer: 0 + m_SortingOrder: 0 + m_SortingLayerID: 0 +--- !u!33 &3300000 +MeshFilter: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 100000} + m_Mesh: {fileID: 4300002, guid: c8a4b06a79d2ea14cab2b7b100678259, type: 3} +--- !u!65 &6500000 +BoxCollider: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 100000} + m_Material: {fileID: 0} + m_IsTrigger: 0 + m_Enabled: 1 + serializedVersion: 2 + m_Size: {x: 1.18778586, y: .251918912, z: 1.78015339} + m_Center: {x: -2.98023224e-08, y: 0, z: .465184152} +--- !u!1001 &100100000 +Prefab: + m_ObjectHideFlags: 1 + serializedVersion: 2 + m_Modification: + m_TransformParent: {fileID: 0} + m_Modifications: [] + m_RemovedComponents: [] + m_ParentPrefab: {fileID: 0} + m_RootGameObject: {fileID: 100000} + m_IsPrefabParent: 1 + m_IsExploded: 1 diff --git a/Assets/QuickRopes 2/CoreScripts/Resources/Link.prefab.meta b/Assets/QuickRopes 2/CoreScripts/Resources/Link.prefab.meta new file mode 100644 index 0000000..e13dc87 --- /dev/null +++ b/Assets/QuickRopes 2/CoreScripts/Resources/Link.prefab.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: f3969805e3f8240449b2bace83fe0d22 +labels: +- editor +- physics +- chain +- string +- cable +- reverie +- interactive +- quickropes +- gameplay +NativeFormatImporter: + userData: diff --git a/Assets/QuickRopes 2/CoreScripts/Resources/Link_NoCollide.prefab b/Assets/QuickRopes 2/CoreScripts/Resources/Link_NoCollide.prefab new file mode 100644 index 0000000..a73d138 --- /dev/null +++ b/Assets/QuickRopes 2/CoreScripts/Resources/Link_NoCollide.prefab @@ -0,0 +1,70 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &100000 +GameObject: + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + serializedVersion: 4 + m_Component: + - 4: {fileID: 400000} + - 33: {fileID: 3300000} + - 23: {fileID: 2300000} + m_Layer: 0 + m_Name: Link_NoCollide + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &400000 +Transform: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 100000} + m_LocalRotation: {x: 0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: -0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} +--- !u!23 &2300000 +Renderer: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 100000} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_LightmapIndex: 255 + m_LightmapTilingOffset: {x: 1, y: 1, z: 0, w: 0} + m_Materials: + - {fileID: 2100000, guid: 75e20fdf21ee4cd4bbbff5787612aa0f, type: 2} + m_SubsetIndices: + m_StaticBatchRoot: {fileID: 0} + m_UseLightProbes: 0 + m_LightProbeAnchor: {fileID: 0} + m_ScaleInLightmap: 1 + m_SortingLayer: 0 + m_SortingOrder: 0 + m_SortingLayerID: 0 +--- !u!33 &3300000 +MeshFilter: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 100000} + m_Mesh: {fileID: 4300002, guid: c8a4b06a79d2ea14cab2b7b100678259, type: 3} +--- !u!1001 &100100000 +Prefab: + m_ObjectHideFlags: 1 + serializedVersion: 2 + m_Modification: + m_TransformParent: {fileID: 0} + m_Modifications: [] + m_RemovedComponents: [] + m_ParentPrefab: {fileID: 0} + m_RootGameObject: {fileID: 100000} + m_IsPrefabParent: 1 + m_IsExploded: 1 diff --git a/Assets/QuickRopes 2/CoreScripts/Resources/Link_NoCollide.prefab.meta b/Assets/QuickRopes 2/CoreScripts/Resources/Link_NoCollide.prefab.meta new file mode 100644 index 0000000..d2aa7ed --- /dev/null +++ b/Assets/QuickRopes 2/CoreScripts/Resources/Link_NoCollide.prefab.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: ea151239cf8ec7a4d84611bb83692120 +labels: +- editor +- physics +- chain +- string +- cable +- reverie +- interactive +- quickropes +- gameplay +NativeFormatImporter: + userData: diff --git a/Assets/QuickRopes 2/CoreScripts/Resources/Materials.meta b/Assets/QuickRopes 2/CoreScripts/Resources/Materials.meta new file mode 100644 index 0000000..aef0fb5 --- /dev/null +++ b/Assets/QuickRopes 2/CoreScripts/Resources/Materials.meta @@ -0,0 +1,5 @@ +fileFormatVersion: 2 +guid: 08396fcaf129ad54b94d677712e75c0f +folderAsset: yes +DefaultImporter: + userData: diff --git a/Assets/QuickRopes 2/CoreScripts/Resources/Materials/Rope.mat b/Assets/QuickRopes 2/CoreScripts/Resources/Materials/Rope.mat new file mode 100644 index 0000000..20d9f0d --- /dev/null +++ b/Assets/QuickRopes 2/CoreScripts/Resources/Materials/Rope.mat @@ -0,0 +1,35 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!21 &2100000 +Material: + serializedVersion: 3 + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_Name: Rope + m_Shader: {fileID: 2, guid: 0000000000000000f000000000000000, type: 0} + m_ShaderKeywords: [] + m_CustomRenderQueue: -1 + m_SavedProperties: + serializedVersion: 2 + m_TexEnvs: + data: + first: + name: _MainTex + second: + m_Texture: {fileID: 2800000, guid: 8f91147309add1148949640554a73d05, type: 3} + m_Scale: {x: 9, y: 1} + m_Offset: {x: 0, y: 0} + data: + first: + name: _BumpMap + second: + m_Texture: {fileID: 2800000, guid: 7c5cdadd5ede8ac4baca46175ebb0272, type: 3} + m_Scale: {x: 20, y: 1} + m_Offset: {x: 0, y: 0} + m_Floats: {} + m_Colors: + data: + first: + name: _Color + second: {r: 1, g: 1, b: 1, a: 1} diff --git a/Assets/QuickRopes 2/CoreScripts/Resources/Materials/Rope.mat.meta b/Assets/QuickRopes 2/CoreScripts/Resources/Materials/Rope.mat.meta new file mode 100644 index 0000000..869128d --- /dev/null +++ b/Assets/QuickRopes 2/CoreScripts/Resources/Materials/Rope.mat.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: d13f5189a59c115459a78374b0d626ee +NativeFormatImporter: + userData: diff --git a/Assets/QuickRopes 2/CoreScripts/Resources/Materials/RopeLineMaterial.mat b/Assets/QuickRopes 2/CoreScripts/Resources/Materials/RopeLineMaterial.mat new file mode 100644 index 0000000..25d6cd1 --- /dev/null +++ b/Assets/QuickRopes 2/CoreScripts/Resources/Materials/RopeLineMaterial.mat @@ -0,0 +1,59 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!21 &2100000 +Material: + serializedVersion: 3 + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_Name: RopeLineMaterial + m_Shader: {fileID: 30, guid: 0000000000000000f000000000000000, type: 0} + m_ShaderKeywords: [] + m_CustomRenderQueue: -1 + m_SavedProperties: + serializedVersion: 2 + m_TexEnvs: + data: + first: + name: _MainTex + second: + m_Texture: {fileID: 0} + m_Scale: {x: 10.5, y: 1} + m_Offset: {x: 0, y: 0} + data: + first: + name: _BumpMap + second: + m_Texture: {fileID: 2800000, guid: e8bb5997f0222cf4ab984dd1ed405225, type: 3} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + m_Floats: + data: + first: + name: _Cutoff + second: .574626863 + data: + first: + name: _InvFade + second: 1 + data: + first: + name: _Shininess + second: .699999988 + m_Colors: + data: + first: + name: _Color + second: {r: 0, g: 0, b: 0, a: 1} + data: + first: + name: _TintColor + second: {r: .0895522237, g: .0895522237, b: .0895522237, a: .501960814} + data: + first: + name: _SpecColor + second: {r: 1, g: 1, b: 1, a: 1} + data: + first: + name: _Emission + second: {r: 0, g: 0, b: 0, a: 0} diff --git a/Assets/QuickRopes 2/CoreScripts/Resources/Materials/RopeLineMaterial.mat.meta b/Assets/QuickRopes 2/CoreScripts/Resources/Materials/RopeLineMaterial.mat.meta new file mode 100644 index 0000000..2491c84 --- /dev/null +++ b/Assets/QuickRopes 2/CoreScripts/Resources/Materials/RopeLineMaterial.mat.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: 7455cdddd8cf6884fb8c267adb8e046e +NativeFormatImporter: + userData: diff --git a/Assets/QuickRopes 2/CoreScripts/Resources/Materials/WhiteLink.mat b/Assets/QuickRopes 2/CoreScripts/Resources/Materials/WhiteLink.mat new file mode 100644 index 0000000..a939cb4 --- /dev/null +++ b/Assets/QuickRopes 2/CoreScripts/Resources/Materials/WhiteLink.mat @@ -0,0 +1,36 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!21 &2100000 +Material: + serializedVersion: 3 + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_Name: WhiteLink + m_Shader: {fileID: 3, guid: 0000000000000000f000000000000000, type: 0} + m_ShaderKeywords: [] + m_CustomRenderQueue: -1 + m_SavedProperties: + serializedVersion: 2 + m_TexEnvs: + data: + first: + name: _MainTex + second: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + m_Floats: + data: + first: + name: _Shininess + second: .537442207 + m_Colors: + data: + first: + name: _Color + second: {r: 1, g: 1, b: 1, a: 1} + data: + first: + name: _SpecColor + second: {r: .907406926, g: .910447776, b: .801737607, a: 1} diff --git a/Assets/QuickRopes 2/CoreScripts/Resources/Materials/WhiteLink.mat.meta b/Assets/QuickRopes 2/CoreScripts/Resources/Materials/WhiteLink.mat.meta new file mode 100644 index 0000000..00cb542 --- /dev/null +++ b/Assets/QuickRopes 2/CoreScripts/Resources/Materials/WhiteLink.mat.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: 75e20fdf21ee4cd4bbbff5787612aa0f +NativeFormatImporter: + userData: diff --git a/Assets/QuickRopes 2/CoreScripts/RopeTubeRenderer.cs b/Assets/QuickRopes 2/CoreScripts/RopeTubeRenderer.cs new file mode 100644 index 0000000..bdebcea --- /dev/null +++ b/Assets/QuickRopes 2/CoreScripts/RopeTubeRenderer.cs @@ -0,0 +1,515 @@ + +using UnityEngine; +using System.Collections; + + +public class RopeTubeRenderer +{ + public bool calculateTangents = false; // turn off to boost performance, results in odd reflections + + GameObject _gameObject; + public GameObject gameObject { get { return _gameObject; } } + + Transform _transform; + public Transform transform { get { return _transform; } } + + int targetVertexCount; // points.Length * ( edgeCount+1 ) one extra hidden edge for UV wrapping + + // user manipulated variables // + Vector3[] points = new Vector3[0]; + float radius = 0.5f; + float[] radiuses; + int edgeCount = 12; // minimum is three + Color[] pointColors; + Rect capUVRect = new Rect(0, 0, 1, 1); + Rect bodyUVRect = new Rect(0, 0, 1, 1); + + // internal variables // + Vector3[] vertices = new Vector3[0]; + Vector3[] normals = new Vector3[0]; + int[] triangles; + Vector2[] uvs; + Vector4[] tangents = new Vector4[0]; + Color[] colors; + Vector3[] circleLookup; + Quaternion[] rotations = new Quaternion[0]; + + MeshFilter filter; + + bool updateCircleLookupFlag; + bool updateUVsFlag; + bool updateTrianglesFlag; + bool updateTangentsFlag; + bool updateColorsFlag; + bool redrawFlag; + + bool pointCountChanged; + + const float TWO_PI = Mathf.PI * 2; + + Vector3 pastUp; // used for calculating the rotation + public Vector3 up + { + get { return pastUp != Vector3.zero ? pastUp : Vector3.up; } + set { pastUp = value; } + + } + + private Mesh _mesh; + public Mesh mesh + { + get { return _mesh; } + } + + + public RopeTubeRenderer(GameObject _gameObject, bool useMeshOnly) + { + if (!useMeshOnly) + { + this._gameObject = _gameObject; + this._transform = _gameObject.transform; + + // ensure necessary components // + MeshFilter filter = _gameObject.GetComponent(); + if (filter == null) filter = _gameObject.AddComponent(); + MeshRenderer renderer = _gameObject.GetComponent(); + if (renderer == null) renderer = _gameObject.AddComponent(); + + _mesh = new Mesh(); + _mesh.name = "RopeTube_" + _gameObject.GetInstanceID(); + filter.mesh = _mesh; + + if (renderer.sharedMaterial == null) + renderer.sharedMaterial = (Material)Resources.Load("Materials/Rope", typeof(Material)); + } + else + { + this._gameObject = _gameObject; + this._transform = _gameObject.transform; + + _mesh = new Mesh(); + _mesh.name = "RopeTube_" + _gameObject.GetInstanceID(); + } + } + + + public void Update() + { + if (points.Length == 0) return; + + if (updateCircleLookupFlag) { UpdateCircleLookup(); } + if (updateUVsFlag) { UpdateUVs(); } + if (updateTangentsFlag && calculateTangents) { UpdateTangents(); } + if (updateTrianglesFlag) { UpdateTriangles(); } + if (redrawFlag) { ReDraw(); } + if (updateColorsFlag) { UpdateColors(); } + + updateCircleLookupFlag = false; + updateTangentsFlag = false; + updateTrianglesFlag = false; + updateUVsFlag = false; + redrawFlag = false; + updateColorsFlag = false; + } + + + void ReDraw() + { + // update array length // + if (vertices.Length != targetVertexCount) + { + _mesh.triangles = new int[0]; // avoid "Mesh.vertices is too small" error message + vertices = new Vector3[targetVertexCount]; + } + if (normals.Length != targetVertexCount) normals = new Vector3[targetVertexCount]; + + int v = 1 + edgeCount + 1; // start beyond the start cap + + Vector3 minBounds = new Vector3(10000, 10000, 10000); + Vector3 maxBounds = new Vector3(-10000, -10000, -10000); + for (int p = 0; p < points.Length; p++) + { + //rotations[p] *= Quaternion.Euler(0, 90, 0); + + if (radiuses != null) + { + // check min an max bounds // + if (points[p].x - radiuses[p] < minBounds.x) minBounds.x = points[p].x - radiuses[p]; + if (points[p].y - radiuses[p] < minBounds.y) minBounds.y = points[p].y - radiuses[p]; + if (points[p].z - radiuses[p] < minBounds.z) minBounds.z = points[p].z - radiuses[p]; + if (points[p].x + radiuses[p] > maxBounds.x) maxBounds.x = points[p].x + radiuses[p]; + if (points[p].y + radiuses[p] > maxBounds.y) maxBounds.y = points[p].y + radiuses[p]; + if (points[p].z + radiuses[p] > maxBounds.z) maxBounds.z = points[p].z + radiuses[p]; + + // set vertices and normals // + for (int s = 0; s < edgeCount + 1; s++) + { + vertices[v] = _transform.InverseTransformPoint(points[p] + rotations[p] * circleLookup[s] * radiuses[p]); + normals[v] = _transform.InverseTransformDirection(rotations[p] * circleLookup[s]); + v++; + } + + } + else + { + // check min an max bounds // + if (points[p].x - radius < minBounds.x) minBounds.x = points[p].x - radius; + if (points[p].y - radius < minBounds.y) minBounds.y = points[p].y - radius; + if (points[p].z - radius < minBounds.z) minBounds.z = points[p].z - radius; + if (points[p].x + radius > maxBounds.x) maxBounds.x = points[p].x + radius; + if (points[p].y + radius > maxBounds.y) maxBounds.y = points[p].y + radius; + if (points[p].z + radius > maxBounds.z) maxBounds.z = points[p].z + radius; + + // set vertices and normals // + for (int s = 0; s < edgeCount + 1; s++) + { + vertices[v] = _transform.InverseTransformPoint(points[p] + rotations[p] * circleLookup[s] * radius); + normals[v] = _transform.InverseTransformDirection(rotations[p] * circleLookup[s]); + v++; + } + } + } + + // start and end caps // + vertices[0] = _transform.InverseTransformPoint(points[0]); + vertices[vertices.Length - 1] = _transform.InverseTransformPoint(points[points.Length - 1]); + normals[0] = _transform.InverseTransformDirection(rotations[0] * Vector3.forward); + normals[targetVertexCount - 1] = _transform.InverseTransformDirection(rotations[0] * -Vector3.forward); + v = 1; + for (int s = 0; s < edgeCount + 1; s++) + { + vertices[v] = vertices[v + edgeCount + 1]; + normals[v] = normals[0]; + v++; + } + v = vertices.Length - edgeCount - 2; + for (int s = 0; s < edgeCount + 1; s++) + { + vertices[v] = vertices[v - edgeCount - 1]; + normals[v] = normals[targetVertexCount - 1]; + v++; + } + + // update mesh // + _mesh.vertices = vertices; + if (updateUVsFlag) _mesh.uv = uvs; + if (updateTrianglesFlag) _mesh.triangles = triangles; + _mesh.normals = normals; + if (calculateTangents) _mesh.tangents = tangents; + + /* + // update bounds // + Vector3 boundsSize = new Vector3(maxBounds.x - minBounds.x, maxBounds.y - minBounds.y, maxBounds.z - minBounds.z); + Vector3 boundsCenter = new Vector3(minBounds.x + boundsSize.x * 0.5f, minBounds.y + boundsSize.y * 0.5f, minBounds.z + boundsSize.z * 0.5f); + _mesh.bounds = new Bounds(boundsCenter, boundsSize); + + */ + _mesh.RecalculateBounds(); + } + + + void UpdateCircleLookup() + { + circleLookup = new Vector3[edgeCount + 1]; // add one more hidden side for UV wrapping + float interpolatorMult = 1 / (float)edgeCount; + for (int s = 0; s < circleLookup.Length; s++) + { + float interpolator = s * interpolatorMult * TWO_PI; + circleLookup[s] = new Vector3(0, Mathf.Cos(interpolator), Mathf.Sin(interpolator)); + } + } + + + void UpdateUVs() + { + uvs = new Vector2[targetVertexCount]; + float interpolatorUmult = 1 / (points.Length - 1f); + float interpolatorVmult = 1 / (float)edgeCount; + int uv = 0; + // start cap // + uvs[uv++] = new Vector2(capUVRect.width * 0.5f + capUVRect.x, capUVRect.height * 0.5f + capUVRect.y); + for (int v = 0; v < edgeCount + 1; v++) + { + float angle = v * interpolatorVmult * TWO_PI + Mathf.PI * 0.5f; + uvs[uv++] = new Vector2(uvs[0].x + Mathf.Cos(angle) * 0.5f * capUVRect.width, uvs[0].y + Mathf.Sin(angle) * 0.5f * capUVRect.height); + } + // body // + for (int u = 0; u < points.Length; u++) + { + float interpolatorU = u * interpolatorUmult; + for (int v = 0; v < edgeCount + 1; v++) + { + float interpolatorV = v * interpolatorVmult; + uvs[uv++] = new Vector2(bodyUVRect.x + interpolatorU * bodyUVRect.width, bodyUVRect.y + interpolatorV * bodyUVRect.height); + } + } + // end cap // + for (int v = 0; v < edgeCount + 1; v++) uvs[uv++] = uvs[v + 1]; + uvs[uv++] = uvs[0]; + } + + + void UpdateTangents() + { + tangents = new Vector4[targetVertexCount]; + int t = 0; + // start cap // + Vector3 tangent = _transform.InverseTransformDirection(rotations[0] * Vector3.right); + for (int s = 0; s < edgeCount + 2; s++) + { + tangents[t++] = new Vector4(tangent.x, tangent.y, tangent.z, 1); + } + // body // + for (int r = 0; r < rotations.Length; r++) + { + tangent = _transform.InverseTransformDirection(rotations[r] * Vector3.forward); + if (calculateTangents) + { + for (int s = 0; s < edgeCount + 1; s++) + { + tangents[t++] = new Vector4(tangent.x, tangent.y, tangent.z, 1); + } + } + } + // end cap // + tangent = _transform.InverseTransformDirection(rotations[rotations.Length - 1] * Vector3.left); + for (int s = 0; s < edgeCount + 2; s++) + { + tangents[t++] = new Vector4(tangent.x, tangent.y, tangent.z, 1); + } + } + + + void UpdateTriangles() + { + int bodyTriangleCount = (points.Length - 1) * edgeCount * 2; + int capsTriangleCount = 2 * edgeCount; + triangles = new int[(bodyTriangleCount + capsTriangleCount) * 3]; + int v = 1; int t = 0; + // begin cap // + for (int e = 0; e < edgeCount; e++) + { + triangles[t++] = v + 1; + triangles[t++] = v; + triangles[t++] = 0; + v++; + } + v++; // skip hidden vertex + + // body // + int[] quad = new int[] { 0, 1, edgeCount + 2, 0, edgeCount + 2, edgeCount + 1 }; + for (int p = 0; p < points.Length - 1; p++) + { + for (int e = 0; e < edgeCount; e++) + { + for (int q = 0; q < quad.Length; q++) triangles[t++] = v + quad[q]; + v++; + } + v++; // skip hidden vertex + } + + v++; // skip hidden vertex + v += edgeCount; // move to next band + + // end cap // + for (int e = 0; e < edgeCount; e++) + { + + triangles[t++] = v; + triangles[t++] = v + 1; + triangles[t++] = targetVertexCount - 1; + v++; + } + } + + + void UpdateColors() + { + if (pointColors != null) + { + colors = new Color[targetVertexCount]; + // cap start // + int v = 0; + colors[v++] = pointColors[0]; + for (int s = 0; s < edgeCount + 1; s++) colors[v++] = pointColors[0]; + + // body // + for (int p = 0; p < points.Length; p++) + { + for (int s = 0; s < edgeCount + 1; s++) + { + colors[v++] = pointColors[p]; + } + } + // cap end // + for (int s = 0; s < edgeCount + 1; s++) + { + colors[v++] = pointColors[pointColors.Length - 1]; + } + colors[v++] = pointColors[pointColors.Length - 1]; + + mesh.colors = colors; + } + } + + + //////////// + // PUBLIC // + //////////// + + + public void SetPointCount(int pointCount) + { + if (pointCount < 2) + { + Debug.LogWarning("TubeRenderer must have at two three points."); + return; + } + + updateTrianglesFlag = true; + updateUVsFlag = true; + updateColorsFlag = true; + updateTangentsFlag = true; + if (circleLookup == null) updateCircleLookupFlag = true; + redrawFlag = true; + + targetVertexCount = pointCount * (edgeCount + 1); + + this.points = new Vector3[pointCount]; + } + + + public void SetPointsAndRotations(Vector3[] points, Quaternion[] rotations) + { + if (points.Length < 2) + { + Debug.LogWarning("RopeTubeRenderer must have at two three points."); + return; + } + + if (points.Length != rotations.Length) + { + Debug.LogWarning("point array must match length of rotation array."); + return; + } + + int lastPointCount = (this.points != null) ? this.points.Length : 0; + if (points.Length != lastPointCount) + { + updateTrianglesFlag = true; + updateUVsFlag = true; + updateColorsFlag = true; + } + updateTangentsFlag = true; + if (circleLookup == null) updateCircleLookupFlag = true; + redrawFlag = true; + + if (radiuses != null) if (points.Length != radiuses.Length) radiuses = null; + + targetVertexCount = (points.Length + 2) * (edgeCount + 1) + 2; // two cap end points + + this.points = points; + this.rotations = rotations; + } + + + public void SetEdgeCount(int edgeCount) + { + if (edgeCount < 3) edgeCount = 3; + + this.edgeCount = edgeCount; + + updateTrianglesFlag = true; + updateUVsFlag = true; + updateCircleLookupFlag = true; + updateColorsFlag = true; + redrawFlag = true; + + targetVertexCount = (points.Length + 2) * (edgeCount + 1) + 2; // two end points + } + + + public void SetRadius(float radius) + { + this.radius = radius; + + redrawFlag = true; + } + + + public void SetRadiuses(float[] radiuses) + { + if (radiuses == null) + { + this.radiuses = null; + return; + } + if (radiuses.Length != points.Length) + { + Debug.Log( + "TubeRenderer only receives as many radius values as it has points. " + + "Use SetPoints() or SetPointCount() before using SetRadiuses()" + ); + return; + } + + this.radiuses = radiuses; + + redrawFlag = true; + } + + + public void SetColors(Color[] colors) + { + if (colors.Length != points.Length) + { + Debug.Log( + "TubeRenderer only receives as many color values as it has points. " + + "Use SetPoints() or SetPointCount() before using SetColors()" + ); + return; + } + pointColors = colors; + + updateColorsFlag = true; + } + + + public void SetBodyUVRect(Rect uvRect) + { + bodyUVRect = uvRect; + + updateUVsFlag = true; + } + + + public void SetCapsUVRect(Rect uvRect) + { + capUVRect = uvRect; + + updateUVsFlag = true; + } + + + // GETTERS // + + + public Vector3[] Points() + { + Vector3[] copy = new Vector3[points.Length]; + points.CopyTo(copy, 0); + return copy; + } + + + public float[] Radiuses() + { + float[] copy = new float[radiuses.Length]; + radiuses.CopyTo(copy, 0); + return copy; + } + + + public int EdgeCount() { return edgeCount; } + +} \ No newline at end of file diff --git a/Assets/QuickRopes 2/CoreScripts/RopeTubeRenderer.cs.meta b/Assets/QuickRopes 2/CoreScripts/RopeTubeRenderer.cs.meta new file mode 100644 index 0000000..6d047bd --- /dev/null +++ b/Assets/QuickRopes 2/CoreScripts/RopeTubeRenderer.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: ad8ba11caaa438a47864ec0880ddaff2 +labels: +- editor +- physics +- chain +- string +- cable +- reverie +- interactive +- quickropes +- gameplay +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/QuickRopes 2/FBX_Files.meta b/Assets/QuickRopes 2/FBX_Files.meta new file mode 100644 index 0000000..7256485 --- /dev/null +++ b/Assets/QuickRopes 2/FBX_Files.meta @@ -0,0 +1,5 @@ +fileFormatVersion: 2 +guid: 8b10706508803fa4a90cc64a38846e6d +folderAsset: yes +DefaultImporter: + userData: diff --git a/Assets/QuickRopes 2/FBX_Files/Crane.meta b/Assets/QuickRopes 2/FBX_Files/Crane.meta new file mode 100644 index 0000000..e47b946 --- /dev/null +++ b/Assets/QuickRopes 2/FBX_Files/Crane.meta @@ -0,0 +1,5 @@ +fileFormatVersion: 2 +guid: f68c639223b4abe42b8cd932d8662715 +folderAsset: yes +DefaultImporter: + userData: diff --git a/Assets/QuickRopes 2/FBX_Files/Crane/CraneBase.fbx b/Assets/QuickRopes 2/FBX_Files/Crane/CraneBase.fbx new file mode 100644 index 0000000000000000000000000000000000000000..f99e5f61636d198dcf1781b30c35cef281be358a GIT binary patch literal 31952 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 GHMs%N0+sy$ literal 0 HcmV?d00001 diff --git a/Assets/QuickRopes 2/FBX_Files/Crane/CraneBase.fbx.meta b/Assets/QuickRopes 2/FBX_Files/Crane/CraneBase.fbx.meta new file mode 100644 index 0000000..7b72597 --- /dev/null +++ b/Assets/QuickRopes 2/FBX_Files/Crane/CraneBase.fbx.meta @@ -0,0 +1,63 @@ +fileFormatVersion: 2 +guid: 51ed34cb4553e7843a7037671e00edf3 +ModelImporter: + serializedVersion: 15 + fileIDToRecycleName: + 100000: //RootNode + 400000: //RootNode + 2300000: //RootNode + 3300000: //RootNode + 4300000: polySurface14 + 11100000: //RootNode + materials: + importMaterials: 1 + materialName: 0 + materialSearch: 1 + animations: + legacyGenerateAnimations: 4 + bakeSimulation: 0 + optimizeGameObjects: 0 + animationCompression: 1 + animationRotationError: .5 + animationPositionError: .5 + animationScaleError: .5 + animationWrapMode: 0 + extraExposedTransformPaths: [] + clipAnimations: [] + isReadable: 1 + meshes: + lODScreenPercentages: [] + globalScale: .5 + meshCompression: 0 + addColliders: 0 + importBlendShapes: 1 + swapUVChannels: 0 + generateSecondaryUV: 0 + useFileUnits: 1 + optimizeMeshForGPU: 1 + weldVertices: 1 + secondaryUVAngleDistortion: 8 + secondaryUVAreaDistortion: 15.000001 + secondaryUVHardAngle: 88 + secondaryUVPackMargin: 4 + tangentSpace: + normalSmoothAngle: 60 + splitTangentsAcrossUV: 1 + normalImportMode: 0 + tangentImportMode: 1 + importAnimation: 1 + copyAvatar: 0 + humanDescription: + human: [] + skeleton: [] + armTwist: .5 + foreArmTwist: .5 + upperLegTwist: .5 + legTwist: .5 + armStretch: .0500000007 + legStretch: .0500000007 + feetSpacing: 0 + rootMotionBoneName: + lastHumanDescriptionAvatarSource: {instanceID: 0} + animationType: 1 + userData: diff --git a/Assets/QuickRopes 2/FBX_Files/Crane/CraneCab.fbx b/Assets/QuickRopes 2/FBX_Files/Crane/CraneCab.fbx new file mode 100644 index 0000000000000000000000000000000000000000..b9370bb8da663eea154d20c7ee69599bc99f7d6e GIT binary patch literal 56112 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 WE=`{cxzxpILyZis=<~+NE&o3+6TOB2 literal 0 HcmV?d00001 diff --git a/Assets/QuickRopes 2/FBX_Files/Crane/CraneCab.fbx.meta b/Assets/QuickRopes 2/FBX_Files/Crane/CraneCab.fbx.meta new file mode 100644 index 0000000..8325e0f --- /dev/null +++ b/Assets/QuickRopes 2/FBX_Files/Crane/CraneCab.fbx.meta @@ -0,0 +1,68 @@ +fileFormatVersion: 2 +guid: 1c68057bd2844a844820ab2d037fd22f +ModelImporter: + serializedVersion: 15 + fileIDToRecycleName: + 100000: Cab1 + 100002: //RootNode + 400000: Cab1 + 400002: //RootNode + 2300000: Cab1 + 2300002: //RootNode + 3300000: Cab1 + 3300002: //RootNode + 4300000: CabBase + 4300002: Cab1 + 11100000: //RootNode + materials: + importMaterials: 1 + materialName: 0 + materialSearch: 1 + animations: + legacyGenerateAnimations: 4 + bakeSimulation: 0 + optimizeGameObjects: 0 + animationCompression: 1 + animationRotationError: .5 + animationPositionError: .5 + animationScaleError: .5 + animationWrapMode: 0 + extraExposedTransformPaths: [] + clipAnimations: [] + isReadable: 1 + meshes: + lODScreenPercentages: [] + globalScale: .5 + meshCompression: 0 + addColliders: 0 + importBlendShapes: 1 + swapUVChannels: 0 + generateSecondaryUV: 0 + useFileUnits: 1 + optimizeMeshForGPU: 1 + weldVertices: 1 + secondaryUVAngleDistortion: 8 + secondaryUVAreaDistortion: 15.000001 + secondaryUVHardAngle: 88 + secondaryUVPackMargin: 4 + tangentSpace: + normalSmoothAngle: 60 + splitTangentsAcrossUV: 1 + normalImportMode: 0 + tangentImportMode: 1 + importAnimation: 1 + copyAvatar: 0 + humanDescription: + human: [] + skeleton: [] + armTwist: .5 + foreArmTwist: .5 + upperLegTwist: .5 + legTwist: .5 + armStretch: .0500000007 + legStretch: .0500000007 + feetSpacing: 0 + rootMotionBoneName: + lastHumanDescriptionAvatarSource: {instanceID: 0} + animationType: 1 + userData: diff --git a/Assets/QuickRopes 2/FBX_Files/Crane/CraneHook.fbx b/Assets/QuickRopes 2/FBX_Files/Crane/CraneHook.fbx new file mode 100644 index 0000000000000000000000000000000000000000..f42077e6aba801e7cc03c158e543cf0abb96959f GIT binary patch literal 20912 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 U#>C^d4rg4xQ0r9kf;R5|3)fw0x&QzG literal 0 HcmV?d00001 diff --git a/Assets/QuickRopes 2/FBX_Files/Crane/CraneHook.fbx.meta b/Assets/QuickRopes 2/FBX_Files/Crane/CraneHook.fbx.meta new file mode 100644 index 0000000..e2c755c --- /dev/null +++ b/Assets/QuickRopes 2/FBX_Files/Crane/CraneHook.fbx.meta @@ -0,0 +1,63 @@ +fileFormatVersion: 2 +guid: ebbeb2f1e7f8ccc40accd54fc043696c +ModelImporter: + serializedVersion: 15 + fileIDToRecycleName: + 100000: //RootNode + 400000: //RootNode + 2300000: //RootNode + 3300000: //RootNode + 4300000: pCube1 + 11100000: //RootNode + materials: + importMaterials: 1 + materialName: 0 + materialSearch: 1 + animations: + legacyGenerateAnimations: 4 + bakeSimulation: 0 + optimizeGameObjects: 0 + animationCompression: 1 + animationRotationError: .5 + animationPositionError: .5 + animationScaleError: .5 + animationWrapMode: 0 + extraExposedTransformPaths: [] + clipAnimations: [] + isReadable: 1 + meshes: + lODScreenPercentages: [] + globalScale: .5 + meshCompression: 0 + addColliders: 0 + importBlendShapes: 1 + swapUVChannels: 0 + generateSecondaryUV: 0 + useFileUnits: 1 + optimizeMeshForGPU: 1 + weldVertices: 1 + secondaryUVAngleDistortion: 8 + secondaryUVAreaDistortion: 15.000001 + secondaryUVHardAngle: 88 + secondaryUVPackMargin: 4 + tangentSpace: + normalSmoothAngle: 60 + splitTangentsAcrossUV: 1 + normalImportMode: 0 + tangentImportMode: 1 + importAnimation: 1 + copyAvatar: 0 + humanDescription: + human: [] + skeleton: [] + armTwist: .5 + foreArmTwist: .5 + upperLegTwist: .5 + legTwist: .5 + armStretch: .0500000007 + legStretch: .0500000007 + feetSpacing: 0 + rootMotionBoneName: + lastHumanDescriptionAvatarSource: {instanceID: 0} + animationType: 1 + userData: diff --git a/Assets/QuickRopes 2/FBX_Files/Crane/CraneSegment.fbx b/Assets/QuickRopes 2/FBX_Files/Crane/CraneSegment.fbx new file mode 100644 index 0000000000000000000000000000000000000000..ab43bad1ae1a6f4bc883bfb30d09f9d4f169a194 GIT binary patch literal 19856 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 Q)x_*aHSWaBZ(sd?0g=`?6951J literal 0 HcmV?d00001 diff --git a/Assets/QuickRopes 2/FBX_Files/Crane/CraneSegment.fbx.meta b/Assets/QuickRopes 2/FBX_Files/Crane/CraneSegment.fbx.meta new file mode 100644 index 0000000..fa88ca6 --- /dev/null +++ b/Assets/QuickRopes 2/FBX_Files/Crane/CraneSegment.fbx.meta @@ -0,0 +1,63 @@ +fileFormatVersion: 2 +guid: e7e3bed7953f28f4289b0ea1e0556548 +ModelImporter: + serializedVersion: 15 + fileIDToRecycleName: + 100000: //RootNode + 400000: //RootNode + 2300000: //RootNode + 3300000: //RootNode + 4300000: polySurface32 + 11100000: //RootNode + materials: + importMaterials: 1 + materialName: 0 + materialSearch: 1 + animations: + legacyGenerateAnimations: 4 + bakeSimulation: 0 + optimizeGameObjects: 0 + animationCompression: 1 + animationRotationError: .5 + animationPositionError: .5 + animationScaleError: .5 + animationWrapMode: 0 + extraExposedTransformPaths: [] + clipAnimations: [] + isReadable: 1 + meshes: + lODScreenPercentages: [] + globalScale: .5 + meshCompression: 0 + addColliders: 0 + importBlendShapes: 1 + swapUVChannels: 0 + generateSecondaryUV: 0 + useFileUnits: 1 + optimizeMeshForGPU: 1 + weldVertices: 1 + secondaryUVAngleDistortion: 8 + secondaryUVAreaDistortion: 15.000001 + secondaryUVHardAngle: 88 + secondaryUVPackMargin: 4 + tangentSpace: + normalSmoothAngle: 60 + splitTangentsAcrossUV: 1 + normalImportMode: 0 + tangentImportMode: 1 + importAnimation: 1 + copyAvatar: 0 + humanDescription: + human: [] + skeleton: [] + armTwist: .5 + foreArmTwist: .5 + upperLegTwist: .5 + legTwist: .5 + armStretch: .0500000007 + legStretch: .0500000007 + feetSpacing: 0 + rootMotionBoneName: + lastHumanDescriptionAvatarSource: {instanceID: 0} + animationType: 1 + userData: diff --git a/Assets/QuickRopes 2/FBX_Files/Crane/Materials.meta b/Assets/QuickRopes 2/FBX_Files/Crane/Materials.meta new file mode 100644 index 0000000..3ab5490 --- /dev/null +++ b/Assets/QuickRopes 2/FBX_Files/Crane/Materials.meta @@ -0,0 +1,5 @@ +fileFormatVersion: 2 +guid: 193cc445caa9a48c293cd09f95260d84 +folderAsset: yes +DefaultImporter: + userData: diff --git a/Assets/QuickRopes 2/FBX_Files/Crane/Materials/BlackSteel.mat b/Assets/QuickRopes 2/FBX_Files/Crane/Materials/BlackSteel.mat new file mode 100644 index 0000000..928c044 --- /dev/null +++ b/Assets/QuickRopes 2/FBX_Files/Crane/Materials/BlackSteel.mat @@ -0,0 +1,28 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!21 &2100000 +Material: + serializedVersion: 3 + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_Name: BlackSteel + m_Shader: {fileID: 7, guid: 0000000000000000f000000000000000, type: 0} + m_ShaderKeywords: [] + m_CustomRenderQueue: -1 + m_SavedProperties: + serializedVersion: 2 + m_TexEnvs: + data: + first: + name: _MainTex + second: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + m_Floats: {} + m_Colors: + data: + first: + name: _Color + second: {r: .197999999, g: .197999999, b: .197999999, a: 1} diff --git a/Assets/QuickRopes 2/FBX_Files/Crane/Materials/BlackSteel.mat.meta b/Assets/QuickRopes 2/FBX_Files/Crane/Materials/BlackSteel.mat.meta new file mode 100644 index 0000000..0540dbb --- /dev/null +++ b/Assets/QuickRopes 2/FBX_Files/Crane/Materials/BlackSteel.mat.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: 5a4f8fbee1ff241c3820d0a888ae34bb +NativeFormatImporter: + userData: diff --git a/Assets/QuickRopes 2/FBX_Files/Crane/Materials/Cab.mat b/Assets/QuickRopes 2/FBX_Files/Crane/Materials/Cab.mat new file mode 100644 index 0000000..bd94d7e --- /dev/null +++ b/Assets/QuickRopes 2/FBX_Files/Crane/Materials/Cab.mat @@ -0,0 +1,28 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!21 &2100000 +Material: + serializedVersion: 3 + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_Name: Cab + m_Shader: {fileID: 7, guid: 0000000000000000f000000000000000, type: 0} + m_ShaderKeywords: [] + m_CustomRenderQueue: -1 + m_SavedProperties: + serializedVersion: 2 + m_TexEnvs: + data: + first: + name: _MainTex + second: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + m_Floats: {} + m_Colors: + data: + first: + name: _Color + second: {r: .889999986, g: .889999986, b: .889999986, a: 1} diff --git a/Assets/QuickRopes 2/FBX_Files/Crane/Materials/Cab.mat.meta b/Assets/QuickRopes 2/FBX_Files/Crane/Materials/Cab.mat.meta new file mode 100644 index 0000000..8f5b7b1 --- /dev/null +++ b/Assets/QuickRopes 2/FBX_Files/Crane/Materials/Cab.mat.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: f7c503e4856d046b69fdc74c4cc501f3 +NativeFormatImporter: + userData: diff --git a/Assets/QuickRopes 2/FBX_Files/Crane/Materials/CabGlass.mat b/Assets/QuickRopes 2/FBX_Files/Crane/Materials/CabGlass.mat new file mode 100644 index 0000000..a21f874 --- /dev/null +++ b/Assets/QuickRopes 2/FBX_Files/Crane/Materials/CabGlass.mat @@ -0,0 +1,28 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!21 &2100000 +Material: + serializedVersion: 3 + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_Name: CabGlass + m_Shader: {fileID: 7, guid: 0000000000000000f000000000000000, type: 0} + m_ShaderKeywords: [] + m_CustomRenderQueue: -1 + m_SavedProperties: + serializedVersion: 2 + m_TexEnvs: + data: + first: + name: _MainTex + second: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + m_Floats: {} + m_Colors: + data: + first: + name: _Color + second: {r: .122000001, g: .122000001, b: .122000001, a: 1} diff --git a/Assets/QuickRopes 2/FBX_Files/Crane/Materials/CabGlass.mat.meta b/Assets/QuickRopes 2/FBX_Files/Crane/Materials/CabGlass.mat.meta new file mode 100644 index 0000000..262a2d9 --- /dev/null +++ b/Assets/QuickRopes 2/FBX_Files/Crane/Materials/CabGlass.mat.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: ebab5ecf39fd64d5a9e51424372f7b28 +NativeFormatImporter: + userData: diff --git a/Assets/QuickRopes 2/FBX_Files/Crane/Materials/Concrete.mat b/Assets/QuickRopes 2/FBX_Files/Crane/Materials/Concrete.mat new file mode 100644 index 0000000..ba1fbfa --- /dev/null +++ b/Assets/QuickRopes 2/FBX_Files/Crane/Materials/Concrete.mat @@ -0,0 +1,28 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!21 &2100000 +Material: + serializedVersion: 3 + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_Name: Concrete + m_Shader: {fileID: 7, guid: 0000000000000000f000000000000000, type: 0} + m_ShaderKeywords: [] + m_CustomRenderQueue: -1 + m_SavedProperties: + serializedVersion: 2 + m_TexEnvs: + data: + first: + name: _MainTex + second: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + m_Floats: {} + m_Colors: + data: + first: + name: _Color + second: {r: .779999971, g: .779999971, b: .779999971, a: 1} diff --git a/Assets/QuickRopes 2/FBX_Files/Crane/Materials/Concrete.mat.meta b/Assets/QuickRopes 2/FBX_Files/Crane/Materials/Concrete.mat.meta new file mode 100644 index 0000000..520fb82 --- /dev/null +++ b/Assets/QuickRopes 2/FBX_Files/Crane/Materials/Concrete.mat.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: 3c02602ec924342b0bc2c4b71ad2c673 +NativeFormatImporter: + userData: diff --git a/Assets/QuickRopes 2/FBX_Files/Crane/Materials/Hook.mat b/Assets/QuickRopes 2/FBX_Files/Crane/Materials/Hook.mat new file mode 100644 index 0000000..e6f5ec3 --- /dev/null +++ b/Assets/QuickRopes 2/FBX_Files/Crane/Materials/Hook.mat @@ -0,0 +1,28 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!21 &2100000 +Material: + serializedVersion: 3 + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_Name: Hook + m_Shader: {fileID: 7, guid: 0000000000000000f000000000000000, type: 0} + m_ShaderKeywords: [] + m_CustomRenderQueue: -1 + m_SavedProperties: + serializedVersion: 2 + m_TexEnvs: + data: + first: + name: _MainTex + second: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + m_Floats: {} + m_Colors: + data: + first: + name: _Color + second: {r: .827344179, g: .827344179, b: .827344179, a: 1} diff --git a/Assets/QuickRopes 2/FBX_Files/Crane/Materials/Hook.mat.meta b/Assets/QuickRopes 2/FBX_Files/Crane/Materials/Hook.mat.meta new file mode 100644 index 0000000..4091a0c --- /dev/null +++ b/Assets/QuickRopes 2/FBX_Files/Crane/Materials/Hook.mat.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: 5e662d9f538f04321ac24a54be5e2fd4 +NativeFormatImporter: + userData: diff --git a/Assets/QuickRopes 2/FBX_Files/Crane/Materials/RedHook5556.mat b/Assets/QuickRopes 2/FBX_Files/Crane/Materials/RedHook5556.mat new file mode 100644 index 0000000..f01d02a --- /dev/null +++ b/Assets/QuickRopes 2/FBX_Files/Crane/Materials/RedHook5556.mat @@ -0,0 +1,28 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!21 &2100000 +Material: + serializedVersion: 3 + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_Name: RedHook5556 + m_Shader: {fileID: 7, guid: 0000000000000000f000000000000000, type: 0} + m_ShaderKeywords: [] + m_CustomRenderQueue: -1 + m_SavedProperties: + serializedVersion: 2 + m_TexEnvs: + data: + first: + name: _MainTex + second: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + m_Floats: {} + m_Colors: + data: + first: + name: _Color + second: {r: .5, g: .113999993, b: .113999993, a: 1} diff --git a/Assets/QuickRopes 2/FBX_Files/Crane/Materials/RedHook5556.mat.meta b/Assets/QuickRopes 2/FBX_Files/Crane/Materials/RedHook5556.mat.meta new file mode 100644 index 0000000..f96a40b --- /dev/null +++ b/Assets/QuickRopes 2/FBX_Files/Crane/Materials/RedHook5556.mat.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: 0598d3744fc714a3a93dd3c3a5997cbc +NativeFormatImporter: + userData: diff --git a/Assets/QuickRopes 2/FBX_Files/Crane/Materials/YellowSteel.mat b/Assets/QuickRopes 2/FBX_Files/Crane/Materials/YellowSteel.mat new file mode 100644 index 0000000..3904e23 --- /dev/null +++ b/Assets/QuickRopes 2/FBX_Files/Crane/Materials/YellowSteel.mat @@ -0,0 +1,28 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!21 &2100000 +Material: + serializedVersion: 3 + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_Name: YellowSteel + m_Shader: {fileID: 7, guid: 0000000000000000f000000000000000, type: 0} + m_ShaderKeywords: [] + m_CustomRenderQueue: -1 + m_SavedProperties: + serializedVersion: 2 + m_TexEnvs: + data: + first: + name: _MainTex + second: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + m_Floats: {} + m_Colors: + data: + first: + name: _Color + second: {r: 1, g: .893616676, b: .509000003, a: 1} diff --git a/Assets/QuickRopes 2/FBX_Files/Crane/Materials/YellowSteel.mat.meta b/Assets/QuickRopes 2/FBX_Files/Crane/Materials/YellowSteel.mat.meta new file mode 100644 index 0000000..17e419a --- /dev/null +++ b/Assets/QuickRopes 2/FBX_Files/Crane/Materials/YellowSteel.mat.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: d939c6f2adce04433afbab64a54c9fe3 +NativeFormatImporter: + userData: diff --git a/Assets/QuickRopes 2/FBX_Files/Gear.fbx b/Assets/QuickRopes 2/FBX_Files/Gear.fbx new file mode 100644 index 0000000000000000000000000000000000000000..f3f7e684b22e651d4ebb8ea8d22790b498c32fa5 GIT binary patch literal 42032 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 A?EnA( literal 0 HcmV?d00001 diff --git a/Assets/QuickRopes 2/FBX_Files/Gear.fbx.meta b/Assets/QuickRopes 2/FBX_Files/Gear.fbx.meta new file mode 100644 index 0000000..2863487 --- /dev/null +++ b/Assets/QuickRopes 2/FBX_Files/Gear.fbx.meta @@ -0,0 +1,63 @@ +fileFormatVersion: 2 +guid: e8983cfbcbd91c14ebb3e84a77527d98 +ModelImporter: + serializedVersion: 15 + fileIDToRecycleName: + 100000: //RootNode + 400000: //RootNode + 2300000: //RootNode + 3300000: //RootNode + 4300000: polySurface1 + 11100000: //RootNode + materials: + importMaterials: 1 + materialName: 0 + materialSearch: 1 + animations: + legacyGenerateAnimations: 4 + bakeSimulation: 0 + optimizeGameObjects: 0 + animationCompression: 1 + animationRotationError: .5 + animationPositionError: .5 + animationScaleError: .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 + weldVertices: 1 + secondaryUVAngleDistortion: 8 + secondaryUVAreaDistortion: 15.000001 + secondaryUVHardAngle: 88 + secondaryUVPackMargin: 4 + tangentSpace: + normalSmoothAngle: 60 + splitTangentsAcrossUV: 1 + normalImportMode: 0 + tangentImportMode: 1 + importAnimation: 1 + copyAvatar: 0 + humanDescription: + human: [] + skeleton: [] + armTwist: .5 + foreArmTwist: .5 + upperLegTwist: .5 + legTwist: .5 + armStretch: .0500000007 + legStretch: .0500000007 + feetSpacing: 0 + rootMotionBoneName: + lastHumanDescriptionAvatarSource: {instanceID: 0} + animationType: 1 + userData: diff --git a/Assets/QuickRopes 2/FBX_Files/Lamp.fbx b/Assets/QuickRopes 2/FBX_Files/Lamp.fbx new file mode 100644 index 0000000000000000000000000000000000000000..1bd3815cd1676aed814dacdc44dbf5c149fbee46 GIT binary patch literal 39104 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�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

+&LgwqnAC|X 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%0Ds>F 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

YWnw3522@jh;in}EOo#TKAkxr-+#g!0XnSa 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 aEcgE=k8|q!h4!&#++g3LPOpfKqW=#iZ}83l literal 0 HcmV?d00001 diff --git a/Assets/QuickRopes 2/FBX_Files/PlanetaryGearSet.fbx.meta b/Assets/QuickRopes 2/FBX_Files/PlanetaryGearSet.fbx.meta new file mode 100644 index 0000000..0489885 --- /dev/null +++ b/Assets/QuickRopes 2/FBX_Files/PlanetaryGearSet.fbx.meta @@ -0,0 +1,83 @@ +fileFormatVersion: 2 +guid: 4ffdbdeb1c2bc5a429813bda18cf05a5 +ModelImporter: + serializedVersion: 15 + fileIDToRecycleName: + 100002: //RootNode + 100010: InnerRing_Motor + 100012: Small_Gear + 100014: OutterRing_Gear + 400002: //RootNode + 400010: InnerRing_Motor + 400012: Small_Gear + 400014: OutterRing_Gear + 2300000: InnerRing_Motor + 2300002: Small_Gear + 2300004: OutterRing_Gear + 3300000: InnerRing_Motor + 3300002: Small_Gear + 3300004: OutterRing_Gear + 4300000: pPipe1 + 4300002: pPipe2 + 4300004: pPipe5 + 4300006: polySurface2 + 4300008: OutterRing_Gear + 4300010: InnerRing_Motor + 4300012: Small_Gear + 4300014: pasted__Link + 4300016: pasted__Link + 4300018: pasted__Link + 4300020: pasted__Link + 11100000: //RootNode + materials: + importMaterials: 1 + materialName: 0 + materialSearch: 1 + animations: + legacyGenerateAnimations: 4 + bakeSimulation: 0 + optimizeGameObjects: 0 + animationCompression: 1 + animationRotationError: .5 + animationPositionError: .5 + animationScaleError: .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 + weldVertices: 1 + secondaryUVAngleDistortion: 8 + secondaryUVAreaDistortion: 15.000001 + secondaryUVHardAngle: 88 + secondaryUVPackMargin: 4 + tangentSpace: + normalSmoothAngle: 60 + splitTangentsAcrossUV: 1 + normalImportMode: 0 + tangentImportMode: 1 + importAnimation: 1 + copyAvatar: 0 + humanDescription: + human: [] + skeleton: [] + armTwist: .5 + foreArmTwist: .5 + upperLegTwist: .5 + legTwist: .5 + armStretch: .0500000007 + legStretch: .0500000007 + feetSpacing: 0 + rootMotionBoneName: + lastHumanDescriptionAvatarSource: {instanceID: 0} + animationType: 1 + userData: diff --git a/Assets/QuickRopes 2/FBX_Files/RustyHook.fbx b/Assets/QuickRopes 2/FBX_Files/RustyHook.fbx new file mode 100644 index 0000000000000000000000000000000000000000..4583ca52b666077bc6844d05fe8a84587065aa02 GIT binary patch literal 42800 zcmce83p`X^_rDT~3aM1CrP56*mAgqoQYe**Ok!e+8OC+OOm~&gMX3m-Qcp=m$Zd#R z5>lbu#+}G@+=iL)Uz@2%PwDA>-{0qdKAkz|?7i1_uf5jVYpuP{iJ=wQ#)@PmtG98F z>_$AnibR%`<(bDLE6Kz2N`UA4F$3y10wV(@l1vxC1Ja1;CPPJZHL-WK#S@%m-A1J=yJpquH7i%YfT2xg+lhCv$C)Bp|1re^rmhDM)Bk zg0wN^lMQiXcOuEgd8DRnY|Rdw8y;ETNDX65jeri(!2w4Y?F0dSKOTS#za3LeNJK{* z$pw#dR$dhf14W~EhjW67sSsQ?5v^Sj$}W<f!Bi&K5gdon6SAiNqr-4;}Pa zJZY4PqW}s_Oh?!x>;M0J>;XRDAJ4*3K9Hptlki}YR`w%i1LAcgx)N+gMF6!t54fCf z9Hp2yhQdqR(a|1nJu;(r;|MmO%0Lox;PQ=wv3N#S z;30mEhWOuRMYh6#R*_;cqev3tAaT9QZ@|zbyvYUIHVTHO-gmZOX5e;$$HMAw+c_eo zZv}r#$y6K&lvXRQQc?soCD~PL)Rfk#ty5aLcJ2BF{6FYkbSyM7mER0?)CLuQv_Zu& zHmEpigJX(h*C0nTYJ-YD*x)YU1Ica?oFMrraM^0*>|$!=hO-$*`S-c3>x_~h5q~Ec ztF1rQeis)|a};pyc!0l=$#?aGbs+U`7=?mRG#+mwf$U%OAIwEF8bzD^1KKxz|Ca^; zSbuV~01L>GBirLghGAf{Lj>*>UaaVNzVuaoY*xz3N6R>UGBBM`J2c{{KSWeygvk69 zRw*ect&&}>I%V znc`erz<)a5;&y`6@;%s~XkIpk<_G881{A3EQaHgT!8&+$Icj_0okx5z9vnUL0R{vY zoGorNf*7EoF9G94WD0NsnIK%aWO!S`?@14GNmq=LqFJCvf=uG~ok9rW3FlI-8l^<> z_HW96?YHdbeszct{eIss^uaR+hKB|_rr*CQ|FvH;E;Z6MhzdoXZ;tIxBz==hj&dO& zpYb#Kzj9E`g-{uV5QYnKXr|Uy_BcH&YZnL`Nbfd8*MpE&pj#tXhl5;oZ-PfSIx#CD za3d*ffD;%&rv7~#|2f(zKtq zm1pY?%UBY+@!OFu^0I*bf*lY^|3KL^ z02=3zLv|+C?(u_<@`nl}ti^D0MPdre32U73XugXqmiTw-JEDMABDhb@i3_%19x`f_K8OG-KX2Y!`U$vT$v-rOSr{o$bzF18d;Pe7JiHt zxjzG-!ToTgKmbIAzd}Qzv_d?N$Wt8r$}dddDHi}aE)njsfV>mu;AoFb5vklz@1Vzb ztwcccZ^sWta2?>02$sVMMu6tpCY-Z12|u#h9cN-Aq!KP6*L#C6a`3znP2BXyn+%C0+|pK#Vl-UHO03{WUIv(kKEF*BFF9U;zmJ@?Hifhzw0_GaTO5&gGwR$rLf6 zy$OEc*t;Q$OE({$fDXBfZLqa4a&wSKuTLbh{@pE%ih&$so7lL6SuEwB)6&x9_ z`95flf}1v+zzm}N_o#OB20FfAHvM$t&+VP-|BwxCw1?&1cyS2od5X9++_V8X;2lJl zk=d$k4U2DAn0_#Ge+MB7Izp_kffGi7g3CzC@Tc@Ux%6BXU>g3-_C~U!m9z86blSC* zNU%kxDKr?334h>GQQPl_81RP70ZoswE)TgweH_sN=RzXK0XL`(8qt^t#XpAhXZM5v zkbByObGBomEP;FcV6vN`;{QvZAl!AX<6+w}{{5@GsXo*sK^&FWbQVlkisdMqCB_LoX#y~hLKw*501+}yT?f3gGbEP(?hT;v$nmpUqqw}FbOB&d zQ27S?=gB-T$QALnc@zXm?wB~2dxTt^5*(z|NNM>BGjzY{vR|m)cb`G85!s(3)3wd=TBFVwZew)>Q zjrkfd#~3=YQ^ew*k5L9TgwPm~2L=s7tmoNDvLZM;T0zG8KP}Dd02#5yO~}y<{u|kv z{HHAP@MLgV+&0Q01ah8DcxOl_t#N2e`G1*OQ^A4!gU7MZf68Mg#sPqk7?C3ZF@o{& zjJoQvaQ_RZ$y`pkwur*}&mH_Zzd-&cN4N|O2O1)GF*eSkq3*0)J!D^8Ga;@eYcP4l@qRW391g>!5 zO-A9x{)R`XHZc4@p%()>ve~tx=*SImZI(NR-!3DNl7(R!B7_yA2a1iGrx`jwmSp!Vpo{e|T(y>< z3yoQCBPC4?X8m> zi6h$~XoSCTAF)7>jL;BHFv5|21ny$a_|PGE2m0Td-_-e|z*|Ov(GdSn%-ZH>T&_L; zZ~P{4ak(iqibMYw^Q0eOkr}KU6$45s#<;T4eZ%pr&t$<*x*0?JKdjmw{vP^uOSyMEO0$2X+&3QOrQcIpd5p_#-oH_f%Prr+-;UGDV_a@E zxs=OBEotn8GA6+{KO>|3#SA~rrQ@!gAjSPY5#iN=HBOI6+KP9;yBHJf$>T}t4Hsif zhW%|ao4UXfihy%=-ZK&afBU8f_BwoWvO1S)t8Ra)#{s%9#LjEV&eMkN8U63`PqCqYl9VGJO-%;^|acA_+-;#|xor``; zHtt-WykvYPf8%yAza<-&Nw?pUjmzX?E*V^qxggs%AlSjqn#=FjBlTRWF>Z<*M}Kc) zs-Q3d=t6(AHHY^3^B*7d&n#?Ay1ofGf}<0Y382Wr#>nMwPRBK{!QWAhtGZPn z#&P=^S96EPr}~X`h5U|cTn^v=j%r*ESA!2i+8(p^;qIp6t;b{x|84T=$Ave7F2HnA z*7Y6!n>YAxv75Qr+eWd`y7oIZ*AD&!`d5~<0@gxE+haC4!T2}9x3oK~2)4LCim;Bq z$M~b*8vA>UKZ>gZzre8a_|L|oq42Xj#$f!>SdRT35QGzkvMFa1cw#&D#9Y%80 ze}151%cTO(jJzN6P`eyQ)6n12T?0C#16Z;mI@GbL9nt+)i-HMISHW$rGTI#WKzWRC zw(#!P4F?}O!I$nX@FomCS$B1GB*NE82<{)-ga~E9>d{WQDDXP%+jmvkF7V~{LG%$n z!3O6s{+EBlaF}vYU|oh-=ZA|P35Pp6?pyj(KND;<-UKg0f5j)D@l*o=idaT)LJz`l z*=lVsJ2qJTstlU({IC=Fs}0KauzQ2BH^T|oQ{jTJzelQ{3ZTKiqn_uY>W!kJ{0*Ug zi&6i4{t5F}5$X+KA`{_mHwnV+Zupx2Al@Fnq#t>CIp*;fh*GeRh3IwRgptDg#xeA= z-1O24K4AJ?)d(*78Tk+l-Tc9^30wlQH^lNk_vm)xZE!>{?q(cfZ_MijWiB0>dq3~d zO@UJMdSL`%8S*;ZtW5#hK!qT+!EBxTIr5W9mY5`~yl+&?u6}7^RrlTais2aqzi58uGtvqZo4O zxjiEat}P(cUws1##UsZ_F6CHLM7zZ39p~@9*m=pN8?)#^4t9qtfq>q9{KC1T?wYw& zV=nx^sOKunH8-;G-wQe@Ah_1HU#_FbY&!4y7Iw9Bz;=&Mp>B z3p+dOpovjY_&u@L#{>djAKqZY&YH0x({Ap`dy@j5&0M>5dAPwsQA3#teg+rh^^}WN zNo$L0XwSB3khrFk?mFvg2G5$6dGi z69Y_VuQ*}LDm)(SxRn)}zim~4cxsY%r;%yZX{VA;U7G2}A!q6qvU{Y`hb&S=8y*>A z#gnb&3T!)We3Tuia3;-ZYHJe@`x2UNq!>ome0clK%TnSkO8O1W6G}sTwj9BNTDb(K z2kG@^(fD}c3@_uhyj4aP8jFVew@4}{Lq~=JkJGy@`*%#?^!asUsJM33S7>qYLjFo$ zqAUA?qn32kF0J<=RPfj3+(^vPTpGHNhGpI02wqXH3f0&JjIr{fMtX(T!3m!nQZ*Kzq}w+61$iBQKUHJiwd8<71Fhh=d0F`K>%)_^+T|ph z#AQwm3lG|MWYHs?3yzB(3bE^=L4GLLDT3aHY-`Wr(q_*O(#9;w) zG{$L=&$e%J!B_DR=5iI^fNHJKhx@~XIIQ=lSDoQ54}B^rPI zDq2x4Lyc&$@~j~~Y0b`-SHl)d6gSoP?h)_v6j-T`dH!LZRca4oaJC0O=VSG*9C_Bv z)2W*og1xYu2BQIk6y<-)fyJjXgEPR~z@wI7Z zzR>o9o=V?diJn696ux>=Lv%`0s_=0gjhE8usjd1sM-CU9;TRlE@H*|3(IeE}cJ7wu z3D2R3qq~Hw=*>rWVYIZ0#Q&=D(ulY@?=7v3#1?#7ZjW)9`!>iJ8^hPMh@!7fiEIm; z5OtzIk#ES=r6}+Y!GMz#U8h1hRC;tirdf~W?e_N6Mw#3IwWG^(7U_T8yP)0^LlZp&nb^={u5*#zKAQv@?$_YMZVzC;+w>mmIVhyAJ-v2{F{2i{idGW(LMZEV ztg?S}g8b)<236&)wCbu*3ouHetELAveIm>cxTncm0 zC$~H*U5VwbtMAw!Kc&jTmtC4nKCnH0A*R7XvT2>Vuj`_&FpCqk!gA`V!B@!+I+#uD zuJa8WhsiRs0Y?r$nZf>$*K~DO-Xjs)dl=WBtnvPn=|j7p+P?abw_zozYi75w<~ch4 ztbCK(LE*=FpI%>aj)|Mls-@*BPiZos?Z^7C-(A;!PtPZ|XVGEUnxXP)1rn*nrZrtX zjKu`Yf?T6VjCS@L*INTBcN3p@RqPN~ekW5R+*-D~df-Y~z$79etHZVG=<`4-etKVq zO^MoLMtIZt$*tbKJAH$YKTKHDzQifkn{cj9*OSZV2y6hYD@u)pC(RhD$Hg1mJlKkdnY zvrx{xm7x|@1uw;0M?6P}N{96v^9JJjWQJuRm}xhLbIoi|#flGdD#1a{b!}^7c2%Wd zA2JMchDJxSMqD{C(!0O<^>Qmo@Ate6#yWWz3=Yyh^sD zxeh*RcR&7v+5MGqe=*DG3|Z#p30DyiHj_R)ug%v&Lp5F}k(kw$^YGK~=75y&*$p$q zjpx&j%%D&!`E!TVo3;#4*Ly7}vD$6cR2PGZembz{zP=+Sx|pmH@l?sljYO_vzi|Nt z*(5%BFnxc8Nnwoo?CL8i9VcQqvMR0eaFI)B_gNd=?vv??S=ip7gIV}wXui`S<5{)F zA)ggh7-o*MWzru`e<*XAQYn0{m9p8QU#GCY)n{Sh;GB3{8f9~LB2?Xvd{vv#)Zhir zgMfn|{?cjjDSFVLB5XcfeO<*|aY{jn*@>9m>(z(7?Kac)$?!iZ@j3pe*Q(kQ6D7=R z+qZLm!CJ)_tYc$z^$M*MLmux3S2dfpW~3DlUQ~%nvh&_-5e@zK&UcC^@wxe7aFyc= zt*I7K!so8siq%?3_&8cnk*)Apcxdfxx=x(&;|-~2W4!NG+siCdDUTO?(pRKSE7KQ% z>v2yq_eRO{uL{LOU|-nuy)l7 zE=659qr-z_(_bd&%Nx{W(Gii6d{{;*fs6LY+XZ}nY`}Eayn@f~j9TQsS{OOH`OB-Q z_lsHF(m6veR<)^akzC{GI(=?}n$Ogb&!(r7FJj+9T%?_d8JKL;k%aM?I{434x5P-E z1269Y<>eknreJ{Z2SuP>sHt~LhyO{zd|tDri^oA;sy2JD&pZWVeNuM2<}DD9JwnmzwXhtt^@&)Edw%Dhva zl8Q7s&`>+X+MUiSv1dsu16p76->uv0@XgY;RU#VEYa+j9FqS(Hws~~eX~v6TbVDs^ z;h)4E9w>6CdW8q6?!!}FcW4F-&D8kfxaAoo#byR)WjnTWAf0nsqsxlVc&JyQp6WhR zt4-{6a#v}Luct|2KJN6b&$XEFsva|?t&O!o+q~`wY1D~}ZzVb!tJ~{K)GJ^addk(G zn-@jQPK>;7}ifEj#vh`wa)xugl*$cMvp>2g@DBoMGMCKXk0zR^n3m znYqRjjp?ni0=<%6X;yPDw6+|Ys9ao=Kr~A6YHVo3Cv}CCd$6Z`p}$N_a8GPjw=+&; zrw?fdNCk@zHNH5_4xh()KFzs^?)9Gb4(sVWtiQ~^DQp^x|Lc5ezUfe?0AYRm25N+1 zfDXH;IZphNajGCY-(IFC?{h%cTe@nk(mQK42ayogHiFuDmM+u2sH!%3ORjBnezxaB zi!bpp_Daq1kCJ9_2FYz#m1nxvuoroLeK1Xz5|Hw!)4l8I4ZGn=>=bI9(n>0yN1reA zdVfz>`UAQoNrzv9^C3Lis;WL9!dFAfamRLI|L`pK3pwgB%HG0Uy34C|C(09)1|K!F zIhWSH3@stbN12~tRITS}o6kOUfF5*QqC>H({%yN}&2;@bVgyTzx6iiJbwzi3>*oe> z_VfL_tt9URt-Qlpf5NMZ*hAH(#?@_qBlm=HS!l?6dPQ8-7V;(|j+*BrWj|sa`Qo*B z`PgdjfD+;vNe%IyE1D|`*TlMb971_`Hf;K?Mp+_X<7~2+hr=rxmhX@>qU);FUVFa)RWR- zzG8OA^LtNlYy9lgES{oYPu%VNsQS?7kXjAmv%q*w;q3nHt;$jAO($rdW7T4PdV;S; z<*l0D!d_QN)TZVii)xNu9V3Hxqy@Bk%0^Ofwvy}k2V@sr<>+}27Hmvy+0vu@Wxp?Fkxz2>#Ll<U5P`!BXwR-V{rMZfo&sh@{^Aua;se38g zsRoqeK@H*!hTXo&3u$S2RoFm9GWB>+%E)~+u0xU3p-81}H_jarO8&~$we03B7-`UJ zTa9DS_1H`0w=4+*7%IO}hhj%zTHc^i=X1`5?nUgmWCN<6<{~;EGC30!hepmjp_e-p z9lL|5(1$nmQjpikiSCaFMMWQj)5JJ;P>>8~Z{XwTV^?Ti-h9dS-lvmozF&8-F#{$7 zk=7=o%bdrsmo&qKXiv5!63`k5=P|NnhgX9YH(CaTLA}QWg&@Ab;)aO=U)qhdMP_~> z?78TFFX>u)d*HrA?E|^GiQ0)l?fg^jsn1%f6e?Wa;hI~V8=4r9Kk zwEOt@=+|7B`lUu%`s#D#%r2Sv!`co-y~>YGl56Kq}xhK5r_m z=9#JkJ#CxD^hgDvinKaX+4EPf8q$$%<_TxAn_|5MXth&R96nbs3%&TEPtzh@%&F{o z22Nvjq=JCOt1FIWq*uBcOCuG;Ez+(ym60;Y8mf^B!XX)^j%D4i_G&DORFDZtH+3rO z&cJJ|i;Ut4dG*1uOz@R~hC*bNNJyIMg3p2(ycJFLG0P`rJBD3}S|a({+bHg!_V$&Zw-~E#O~=S_&O;bdN7SS)7nm-jcBl+D|*M2-=@{IuY8-?eT~9 zt5;<3syJ*ru(Z8>!n>K2tjfxgsn@F82}h>i2C98&2Z2ia>11ecxaTaipS2`hQFSIgL1am!)<0si)axF@Tm+-=R3ub)YJ5vBh4b>-(a z&$O9Pt7)|cYAshyfm-7Avq>>g!dufSKbMGS)wSEV3e-8e$MyO=12F!yInbPU{v3DP za@je40#0T88A~c|ojfr4LT2UX^)vOV+wCRzGo0Mx*h`@KnT%D*QjrdmrlPJ+TFF8u zt5@*=?VjdF%Y8OF1CU|(TmTBYy%c`$y_*DZYwRv0y>L+NNe7DpQF2L>q(Ot?q=olmmG)kRWq|Ii`^!juW3K5E~x9|{zB^Hf`p_pe;q3TkPjCD zfGZ{<(0u6<1hcjtHRta}&4tL&{MJbgXkMU0fac<|;?Ugpq8L3FpEOAob#jpo zPGlw|CH7)PgrUg%tS=x)Wu^my^uap9ks+QNPQYk@h#1t;MR?&CBO*o1!w*d=a&%7- z3Y)(S@Tl_z;dfYe4g4yKOmR0ePw<)oc)`Q+4MI?sGe89n?oI#71z!19VH z2ZPQ%tRb*0`PbM^XK0rZ24-mJj{)Uhn@ByM6r-?+0~Th!jI|nQJ`Tu%vEVy>z!Kh* zw7_n!O>aj8!u`;RH=jG074Dci)UJ8u04=c@3h;ZQ+8zDYC~K^bY?DYhmt7N!J1&us zG_>M*`Yvz`^o&{X`?+QfI2B39Dc~fG63!;2D2OL#R#w_xk|+Q#k;mHvPN?B@47ii- z^tsTUS+f?}PjnQ7_S!1vl9G@|t*qQV2b>lG`BV4!S*IhQ`T2BFX#Top6*QmWh7cs=Ol8^_lLnF zD+qEF!R6|{#?*lqUds|g581=%;H8n43Ugn|aCblmJ)FU0!$bXm5_&j}K|vvK zKny*c#vmG`KzKNb$@JbG7ppSQ@~V<@{Rsz;bp;xt4$CcXm6GMkW+!V#dmGQ1oUZOT zC|z!mEEn1FEI(b{iC-`F^S~0zp}B1bmRMfxsI~ocraD5EJ+*u`MTgIMaBf^W%S$ve zZ1oJ*5Y@G+!}im@+F}o>$-Yih?Cd$6Rn|% z)1MJGq{>mI4^sw?IFvdK57l_umpalO4Yz-0K2A)2!kd3!3g%HZ9-@|qw~@Kfo(sy= zv3%(ZlIKT8En1N&;Z(LSePZ(J$f$L1vx6PW%F;BFmqtb@oT{#Bb;k=kJ9fNqJ@z@F zzfA3wG5SqkQQ_%u%W83ZO5Dm-y#1EuX4m~aqoX9YW|TXXC1&ib@MNz=6{gU;qojev@2$1g#}nOBpcn~Vc0fFr}# zZ&~g*=Zt4G3ScRv>t~#)KB?jmabQ(@3MJ^k9Kd&&Iu-EO&mIJP2>~|1`1zy)%;F6) z03&u=8DI?F3CZN+gQsdbb@V1}J>3q~_qCOw`orzzP(Ak@>Sk;61wfna@+zgYPs}9~ zFeTKgO;sG6!!=Q7B6hw|4KWNVWcER4<~&i*nZl`SfHqrO1aMxzn+T&`vNpSkRCaBH z5)y~u?I}=!dp8FVrk@%D!hOD^1JfluyMgH= zla~Y2>rONP&b*8@teKHfQ&zkVCdHjRTunFgs^pz$C4}kkmF+C-&QFNe*V)$D!Iv63 z@r9KflvYIVX6dB)97&hT#QxH0ePg#H(WZ!yNoHK}efEhfhc`(MysE@Qna^lo$S z>(DpvI+W~|_cFQ9#T>RcE4a!s$h@vHC6(G2P1R>hLp9|rhlQQD z)MV%G8co%A!kY^|T^n1RGyWF5a6{RDpY@v)yYO;*R0EOH!G!YKVYF*3PS*bY`%R1R;#;oZK*VNp258rsQ zk2^WwgIAi5SEl=bG`-1Z((~YyQ!|Vf7G=&bUf`p$aT#8+ZsCoP1wI;rOYWRf3Ut1< z?C^t#ll<;;*-PSevE6iSIxe}gdIo4k0&<%7vLn_#zJI!_NyG+%B4|)RoEy8`Y_~+El2%3uvF}Q!DVOeQH z!M1A&`BLrAv%IA{FY1R(-@)tT>oC#JeH_^A?3pH;rr0iNTCwY+i9YYPkU9+qmv^uE zjy78#o4?ZO#`dhw(c6==v={qD{sLYD2iUjbf0Av+RYAv18&=IfC8|Ahb>^iFGji`b z2D*MU3q_^$3`$hF|_-k7})A9;na^1UJEo~5HmI5QUe$ zPi_nCywLPjq~4EDY~vi!O`uXOUhiyE+^xg%*We@LPJ30@4 z|Mc#%FL#4|d%7XO*<2T;hUtiG3pf1fFYi zY1>L>GFJ?k@SFR7DTZq0QQ*!gBMk3;nXM*a-+kRy!`4SOWx;ikS7&9<&#B!kd(LKu z$`-XzZgV3q9^A4t;>4D}9^MPpyUCTof|MSmoK8TscMv}YS1)dOpxgo{hy~oB}b!g#uk-J zo5Tz?&Pmozet6gE!WA3RdCBf2;b&(Qm=x^&>%nb*{+lY<;gUfP%7=HQi;fIlz4(+pRh>ZPUpe+97UYPcoxivu+Ru`t+zi#DE zo}G{`zk=k8+r6hjy4C(^Zlp%z+``ZEH&fD2iReulI=kSE%8bnmZp`$*To5cNe{#k1 z+(pPf8p;E=YcDGPxWia3KekhBj6pMm^b%fuGm%bt!qXguYkRG(dOnUxUp(Ak8rnHG zEN1zh-~+;njAcVAY1%V3*FTb6e0pb9^>E>3 zqwxR1NB&$Z`m3Vo%cYIvA9ir=a>-!phG)+AKMeCvLiFXqCOirLa6}T9bKZsUEz>Bs z&NfeGjk4MY-(`7B@Vn)nCawD-E69JM*;&5V%cq_=W|=M`qP>bP8-DEe63e9vriv~& zZ?RE!=cRl7CSn`UT@bmrIr_bl;Jht&H|^Uzm3PYVIkK>IwA8)ehO_1Rrn+v6or#xr&`Z0Wc9DA zq3ml^T(LU7Tza=fJDxLigP6L>P@dIT8eMp|gHyGrsgr*ENw*gpKD3TXeRWDa z(W^nNNIUWDmD4i*(G@Gyn0KeBlPK+v$@q>a@{ZJEUCH8U5r-{nkKL4Sh`)@LXO{HY zxQJ%Ay6t^L2uSd;54+ORr|>Y$n7ORtc>l*m(Lq2F$s{)&s;c@Dmlr~^o2%Z{ze}rh z7n9ECA}T+b?pkX$y>+v+S1v8KW55bJK1JWc(aFU)^+c4f&MviGxmDchd82-d{MErP z-ATQ4hmJ@gmF;D4=cnX0NDLyniptwj)Yw6)_rge=!Y4z=8*8;0v+w(=lu5fia-I9e zZLv|bjOLIZ@8(FaMnyo|caA>o(}77&UJp$hrmmzj_UaoQ(mW^gWr2U((0=&}W69{Q zLa)Qv_ebK(zAP<~SjW728tUAygx=btQuD4-CXy;c_dYybft@h-tub%*@YU2vwj1@v zwdu_Zj6T(TeIqmQ%=UUrFP~!3bBE!V>aW8nPE1BmWmxPdy2lidl}w5>qw1{$(O@IEbm7{mi08b{b_iaIcnAiYt|J;y=BMjt!>3$3Hen(^QN@)W{;$F(<6`GscoL=fjGIo?a@~pV)*3i$maZK!Pij>;0VowKSTK-N; zLHc0US(gdf21%rhfJgqML8e}~uZrcsO>w#zqyF><7cVnq;%+b!KWuz9y|vG2USyZw zW^tzzS;OzjlT(6=JN8~_Svwg!#LKKoeeVyl6v7y=o@5$_Ec9xXxU{m?&huL0+mj!3 zG7E3Y)QuJdCc50CoRv9Ej~Ygn6gOnV7Sm_En@2wj65qmkF?|1WeTJb-QuKEGBV^^*}wAkw8ZAcr;2`AMklSsbY0yS6qOmk3hj>F!Yym!Y~W4r@VGnu}vCJUAb1@YmD8`es(U9Sd$%Q zmP$MFEb^fgb1vB5bIWH}WJ>r_Cx1CiSs{`C{u z$l^ZT9^K~tMQf#_@$CZ@#!CwhWkm@H-@oTyH#ICy(Yv3nD*tZH*(bfa+sj<3Pf~fE zKE|IZikU7?n5WgYYM)xo9_%R>QGM4BGx7u4mtyTw?7p0i?s}-WG4X6fqEpXf)3Xvj zitaNM%>A$}OV5uKw=L>WaH@3U?YoP6H{gegOihw2Gu#Vmxd=T2ZFMnXRgUC30{2iYbAa;!Ei*3;bKIv7Cn$dWXGh<6p&tJi$VIUI*cZ zb;vEh*B&7Jcu)lbvG8{F0gLDN6VLI$)Kl zk2*HGxtG~?5F@pPmGJhafNNbmg_pUg;V$iKUP$N5b;7kCi#Sis{4fe+)~drks4lH2 znQX=g3krKG)OCrz0az`sl-b@Yzs>x!7{*}uMJgYFY8SVzrQXsEY@tbFJun~ZBxprP zlqpl3Vl^u$`9_(gY}-d&67=_V5=fM~y$a3!+O_A19~mnYoA#Eqr*1DSXLt9q)*hj) zPt|26(iDas@v$y9ti4nIhU}T}>_(ZH?3-t)d@U3GOWkVjlcbHk8urjnxQIs1qR3@O z?#!x5WIg8y4a`Qq<4L((VRX5E-PEl3B}nu^11Ce`hjwMD{bf2zB!8H4H}v4Su)*l= zC}NQt_@J^-%)Zw5xhfB`_I5u#M%<1Wy=DiXm%}DX0z+(2lOCz zT(82L_{6gx4zqAnBXT4~&oFXGxz+sG%G$M&mbhpD3^Z-4X0FH~A}$E30Zh(|04;5nS6;q`RsaWU#kZ`3)pW zMG=t^_I}vH&g?Sl9$@;gf zA1Wa$J+u&>pK6xcrQjFm?l0csnVFkt`Kp+y8s+#Hu_AUlERVII!0e^;M#Bbk`kglL z*C#qp+6U}uEOKGM0FhHvX~;{St2`(pVR}n1KcGv&vJ476YCO+jqaQ7y56*Tdr91#5 zeBODb9vj_yIHY96B8;3VQNz1iBHcB&bsz8+dao@mZdn~Xa?m|hj4Zm$MlJO{AHi4foszAW|-6; zde@vUH((vDaLPhf)77-q7IRfmBW2JhrJ#X1{~eJh?4$~%JM6klRml2VwZxKC-zKIk zGG+OWRrj-KH>sfmWKONd@N6d1QQMW^Rdk2JX^rr%;;~vMSl)V^#ow)Z_R6pYql5kzv;RotYer5idVJ6pcdAn$7#Y;n>DkrtDq zuGL*tv`|#r-hBv(IAl$9vVXs!rJdHAXdi-ml)S3ehW%*Xz!F_uEq2<9A?oVlzuwF0E8ZG<94J%j3=CGqowa$VqkS58bM2s$Ez(GNp^!F6U`5 zwFWP}Wo+FiKcX-E-QoLA znjD8FWzNgqT%8A$SM!xSHCmJF-M(TjA+d}3-^^j~b!YJY)j{qNQ{3*okv@?%qc&4r zOZvLGnf^-?D?Me+kY?`D10>OOZgbS1UZr-U_dS>`X(dV!0Ow?}Fop4yMC zOnqjLtvzz9hrydx2ovaxkvEA|M!OJ=ym4FGy=aSvY~KN+e&H-L8_0CZQXiyFWNV3I z)19u8KgQl=tgzgY6iVlt8+MyLKg!shwuM$2&@NnDI4SMRmp21jOS}V2_!yNOPT)U|z(ulovg+aL5 z-MWqOoQF~n37-VDend+F_JgM7;1DO}()#GTvuxKEmYBg5GDxf}rUt1s4BV61JHq2; zPNhVtWX6!h+^`~*sAxMNQK`{?XjsYcS&oKz56P}kLdM@_5F2L=bbq}@Yb zCK?^>G=6KmM(e|yfvMfRknh#@Ss!MtNv*MbRHu}K`of=i{KkvMDJdTQn#>)u;*W8Di#b1_IP5m96Z!HI*qm=J33+<-%HzY zwti$P{Z;-s`aMnf5cLy7=`6#oIG?1sB)9j@gCV~Hr{e=D1AYYl5IvXRU>i$+OZOS6 zXsk~AYHU+Fbi405?ZbqZ7eU++Neybd1bFZ3PV~-tUu7)r7!n(qOQPp3vo^b1_rwp& z<{9yMdbPr9sQ0h3%t5U4_3MII%8Q1@3|SBhz^>jHpNVK~xJ!9n5XQVXh`kPhY6h)@ zx}w)OO2)b#DP<~g&Z|-RnG?X!Qs2_U zlRaZC++@NkGZv<1DXq4gON9zR?sp`D2RqLj!pZVoI^v_A$`#Y9sKEJ1M&=(EuS9_?Hsxzmawc&!g|HjCgTkC_*QA&9 z^ZuAvsTZ1WyyaY|VlRS(o1(rd&+bupU&WYG8zhq5O4(81X|9UdMG3HGohd#oxnHs7 zz1Ld;D~H(gfe(@hy+Y4ChIu0N=8^)bx}7?6No`^&CIRyx+Dp-CWwkk4HDu#Cc>`0s z%1KnQw&A?U!CiIcYdQ_VjnAWAYijBl$cpbN^Fs<=G^`yO77;>8)h*3y-soSSZOD$T zbzdu75)YAc`~JiZe+JgYE@>Icb098>ZHh0a!qQ}<6a8`tDfi{BTUgyp6Z#!5NO3J0 z>xmz??+h}^61@sTk29y8Qu#}wfwJo_)ARHRqiwd4pG@v5vuVB`av$~*g8 z>5ozgCvV$sT|spZHr6~|2CL>%0+d`<}|^-v7fWC0r`6J?qnkmkLzXVRM~}h!&Aq=VQ%AD+9y2{eoUG**(TejDg^}*AQ!FjIj(rkbw4?58 zlP^S@o-*}9+xG5avj=Dm`Jve()jnWFVYb^%YTd}X5E9FcjhgS+re2a_sico1%SWf3 ziBGnY4F*GWAkyAN3c0C#(`Tz!WMTI1)Gl4k)FRywyB7I8#`mR{Dt#*?G9WRl#Il~N~z4^3i!ejCup{M6?W zHL@}tZaDh3v`IpqthK&d3H-o&whohAY!n*MR?qyD1H;ML>-KscO+%(Um+{P-W7g|O zjLM`Ip1fvpqE&q08IKCNuaL~KT~(Ofw|p1&CQZrDdp{#uo0Yr?Sa2Y(R4%=j8C{sI zM-hgc%T`!lCJAI|OevM-~$F-y>M5qn2W-yVvV+r_%% z_Uy;Roybu+V0Y5bQm{MTgb90E_E&d{4~2?1xC8_TDl0PYlHarTvknuh4mEj;^|;@( zHDu{^2rXlzs}8?e4cjshDq4ru*lBf4^s19EzYE^m=tjqzx>tSP%l#ZbW~a=Eo`ZFDeW38FH>M>7?hoHLiw1>QSZvd{FQA=!i`dl&k`T1@Y*VV9}JHJwDs zXmX+9+Vbt*av%9Z7UarQwhxAi=R1QLyivULJ4|QX0iIr<2%JUqw&oo2w)9SVzvIIfm5<479u}1+`z3ETwdr@VSSqfwheA7h zWxAN!o{aU*c+DbD|BEZni)j&Mk`wWpcsvhTKyuvB_WVT;@-MSo!H@y2h z!l}^=ogQX9^I2JF>AYG>c8!%twgG^W(o_d(Jtb~*22bLs3l)J|@s+7~cFVxu+%CClXoDaPcL4I1!2TXrB zZ{Ef3YpcL^F)bNoB>|?KqQN^F5kt)%Dw0~rRmE5KW_!14rFKkp5WnkNyNN7R%JFv% z&KrK4NGV{mByX?UP|}~0nA(On#~76hH3(=1Om+~@nUF}Rzwv^e`dl8>^@6>E{^6#Gh;)dj?a)eKG89-6@?q$NN9YSThT>V!h?jgoiG zH`W-_hGwTTBHs1sI>p&4m~}YQ56`6-TMq0Cebp))Cs($zGj+wh<+1UM zV8Yv8N&Sx=?}TcF~Sd?vJEu#snmSR3M2(%5PUN>Gl>>MSJ?ghGgPVm8vgt)5}BV5?xz%7#Iy#ms@Bn7 zH!)S33WHx|H#Huc&+30#Gw&_&7=c%%Yw&ZSll1O+uQ+MZlqq3~gW~?Rz5PSCcJ=!% ze_QQ@_SW+)Plg`g=vgyN?4za<9-bk~q~Xft6^T`TO)ytkF`*_xPptje5v4$BP3hEqOZ=-x8Zt_RxYkMM=@_aM5xcYSfy`@q80KQP2xoo2aOSxV zYys!3amvt!!-W9~o)Ry7k|Led|FVUxdPNIo)z(yIk6)&7Mrd?mI2LV+U^MI2)Mmf- zPdPu(zC3!3OtDgn{@D+dF4a_-B1L9)(MRDoJ^^M=L$#@!B!}x70_2_q_spb~nlK-P zf`ji#2&#IS)-}6CsX5^66++dSjy#7dOrwk1^!{1_Hmp&NZaOtQ3k-|RuMrT#c2GC4 zC-%vubtwv$-)wD)y=t^5wRFgN18oC)NkI9j?3nIjmzs7+WkrYNvDdb(dKwqj?^AU5 zin6r%km3W|j{zd`w1tJ)l-3vz*+HTXX`Rb9Tjd4u(VTOL+Y~ zkGx+|J6Nn-+qELBqMPj7E!ULie(W< zim22|M2kuhNMti0fv|{3fW)PW3W^pLX&|vGP%07@6%>+yY_diTOOPFeutP`!+4Id4 zg3JH5@ArQH`M-b8NtkEmUS{sO=bjbyefz+Ze8h9K_VNt{I$6G>oi=gDv6v zZWHMu1d(1&{Z(74@p?~^h)!s47(UD@IcCAM6~;n8t?=PjnRy29Wpz;Jzv5mdSXFZE z=@*}c6!2vP#yrWMIr3MJCH+>CDR*V{=))A^#N52Vh!-b2$8>!(g-fK%JM*by!p%YK zsz>9($4|QTxa^=W8%&1n&c>sulCOC!Fc}=fthA#b?uh6k?h*}Pznw@UVk1A)!T}5c zXhUJ{RC6oSOW~d?i`}WcL^Tn3&v!EJapkvG10!6LF9LMBJZ)utyHzI$4fXJ?J3P>B#H&ssdJ&cxU4BEXL>uwi{ZddVQ&K#2X-s*8O zxz}~N9uB6sXk>_I+|L`z%gfTi42AFn{tOCs`hpqtEo&7sL&g-8Tf2D8?LB8G-52sKmI)=5jSv zeG0b+vRl%cdYWzxvJY985WnGKg3<|!+f`!SGQHBVlx;%Uqh_xyc|ahDYGv3L6+>bt zmpbN;x{&rHKt8Gf%NBH z0I~OZQl8)oqSe##4lvYp$bQ`{*z5zWG5=!~%ah05t>=Q@R1E{JB5(0*uUh)b?qQ(V zsQf;cLQ2jyqLMBy#dph!2=nEaDcoH=@pD)#?CsPUHv{An$3f8_#y!!kT7!CEvraiu zp-s*k6uG;UYg;(n1FvEin7jW1$f_H8C8@En71QBDM}AF)K0Q@~Xw_asK=4$a%!4zD zn}xKT!W(ybOQ!qvtHVfX&u>BGl8Bz@l}ME}A2WIDu3Ca$KXm3h3RX;)jbJOrL#z9m zjhRio51^@=<|cWUybbm|A8> zFK~n7qD^4a4~-4m zRr2l+S8DE%khWK(if=o(lT5`PvCXs}1w9&ZReB)$b)g+~5=Lr$4YnNwcuw4`iduyc zm6p#MEpB3VCq43$pM@5dlRbY%)IHX*y}3%?RWTV_(9~ZB-cn1tk;%{za^e~3kC)IuMQNBTiU%P z=30_2fQ17L?3FU?3L1D~OouhZFku_d!>3Kb%#lv#JO!o3r2Hel$lLY6IlfL!(Ub@o{UvRI{L=#_m?ga=boMt5*wZF z1oYGSK6(jq(e8Hq`HqUF_b=WuZo?FFH5H0Z+qLWIg_CowFa9|$r6fx$u-JwEX zZr(}R+)J)DuBG7p(h#+#X;X^{b|N%woU?iA+t>?47+kukqvGu_;u06n-Ouu%Uh6)` zWS)L~7)={dl<{jzY%E*tI+myHVUi~6-F&SlDyZFO-l8#m;R|ofCBndZh#077**k94 zcB)QVNV$B0IA#~=yM@;DfaGyNQMv6dUpbg#ngh-UeN2MeA5Si6eR{g-$WhhFrr8l6 z>pwf$v_@UA5XhQ7*#uoU;_n`~?Pqn(|L}Cv6*b!mAm*P>H>ob_fi9mqjGsQ_#EY43 zpfk8rYtE6QUT45LE$E1>J$ODd+xuAfE!~D}1}wc@T zH4Qn7<-ChMyYc++BNMaPyNz&H51gH4`la)Z3*pCa?73(2?3{aa{|{$P&&K9kEnlv6 zgKH^25*3v{-jp=f`WKDymrGtin6muKo-*raPq&rNd&wb6a_RkzQ;cq z4bmjP96Jtcmkv*Q$@khvOoYcw=qpz`P-XkNVWf#089Lflef_-2jGJfvGP-+cmOire zjHavsQTE<3%Gat)kcJ>lEVsj$KjplMmpFFZ)Vq!_@%`-){`E#XnA|aHkR?gs{plc2 zXSw_=b^Xm~swCEL-7ms37HJ0b$-`Kuj>UBSD0KYwOoT8EA#ud4juRdx4aS7Ug$Oim zr{+tppO_Qh;b>2M7tew>kByh59M~DjyA!65@R)c*iA0yYz_?+U*7nUhl%dLL~Fsei34(AB8nf)d^K@7*Q6$6e9wIxcQFQ2ko64qT|8$HVeJxJrdVhL|KG!4Lf87Ewyjr&=(JiemCs!ks(-9Mt| z&{U~gpFTJ)CW!{0I5H=<1^yK`nURng53g(4qG*k?bFz%&MOEuF>M7zuLX{bJN{h;^ z4HV&IIn{O%y*)3)6YXyM&_wjY$vBR5=mPd8-lpN@d;E=-x5ZroS{cKpr>#;k$ZdCh@VOLwlhX(^T^B#zSO<~;U**E z%Fy{ItRyDrDw^bHL_@s9PZ8uEVbpP)_xONSE-h9E{?v(a%1vDORmXi~Ix;DLm*loM zkEnT9;uz7(&(DlJUF8)GA8lfHE#B#65t&Y(NExcq-7VBd(1?2y#_GKVM#7ZI_dPEr zE?Vr#!ZK_|Hw=VLRzIH;4Fn^oLp4q;%^tp$s4UUtH==NF6g*Nc?GaxxUyb;Q8n*q0 z_DGL|D{f5rgCN~{+epdPxha%n-E(o~gq*<>MntkQW<{h9Quqidba{%kB1bJ#yf;dX zs`nZvCb8l@14&}T{pUs=5`wAUT$!*LNuUMLPG>n!ZcNKQOz97a_(qFKVn%hUH#eM(c1avZ?sG zQ`C`r&hv2`GhIjIOwAAY_Du<)Z)%0rkwF8x;{tsJXO>U^Ghc*Y7tWb@%8#4Xf?qwd zSJv9TwOwi&_^0p+hVd)ct{CIV%E&bZ7)^?6rBz;sEiXMr!>byl=O`{ z=Jkpx2Rg(03QK{Fx{Dktk&WEFv*${bXo|4HVaT8BdP_Qa$`PV^VYG{=A`^ zC)4biU-g1QYK)e$B!NoQff2Wbn5^C1xr_|WA+BBMfp1Qy1}*M4)LP}L@hq8m7ELQY zSgI{7y!!|ra1q8Wdl>Y~R4Doq7gM~G`_)h-|0Q9f@R!HT${R$U(;z=#kpE0rMBL+i zKU$j5=*Ws;_D?Ab5!C+I3p(?!y)TiybaV=21}Zq6sLoT0qnocqnvY#bbm}Ft!&&k! zS(hSE5r_;|WQ>|g-^%2F9atkZ zqWC0kRKKQQF|O!=KEz-}2-8COX9Dlf1VT+`V?OQt9T+jO-`hHzn%$nn zt*@4ri9$N@Q^>R7Kk4@l$%!(CZD(@cu~E-5p5?dt(&My3mfed3xDADi!D`U4l7(5o zs7Ho9FM%Z(7e(F8Oh9YdBg*;JPUcDd!j~zp_v>pv2LI7L;JuA3K!#HjcQL*5Js8dLrXf?cd?9D13ID6Modkr%R=U_4`TDY^)#E%f=+O(*7QKh`h zk^{0IdbTl~Xn#~={z$E+@f;bc2H%iIV9K0G*h9wgYpr?pc0@_Un!E)_DSYtTDffzq z*YI;h5XQs<_=M0?0%swY&?;RbI-fJvqnNn<tT7J;s%ODHv93xj>D{Vn5=Sa)GJ-e z>i6R&2w{AjjMw6)PbBT0XOFOalBg3mDKN_e`@H*%Kl$s61XJ%`P1%&ES<9pFS9@UC zy3?`;lrOy9_$k)%l1l{!q!#7f9$3xLkSJ}k`F5Bm^C@gs*=(u1`{S?EU@Oz)2P2gf zFK}f7E}%1aSW{>;Sx3?!QRVl{M>KmMSPS(g=L)l6^^}hIO6uf=iL}W2{fJtsbj@bc zJMF=-Y*;<=DONt;>MP+<(pXz&4r~ziw2^pFd3JITpZi|E?HV=ewGf_<5j7y6I*~}F zws-LY?W5u%Uu%SOCuor;zJlmN*ZyU!Q|^16bofX++;*@@=+p3M0@2#F$x8cI2hx0f zN@Wq>;b4JfpsQ?6ID*h+T5OzJ$uDK=o~1Xf?iRlyT5*btugpE8Ts*0zqa=un(6t8R z+Vc-DW2~mF^sJLrv`l~l*c$^M61r2rzy1J!#9_SOFnn#n*y1j>h`8@k=NM_WV&mxg zNRzmz`N}clMeWl4T}?9j{pwD$-!XUThq}`hSy9F%cNdkB`f*1sQs@)MeZY`Lo|$b0(F(W^5>Rw zzWDb3)rOPkXx_M4*x^~vG<&55zHO__uTfpX9X(i~_;;n(nxqxA$|d#@Y??tIGpzgG zxUtr;0~X1m#DWu5^4BL;WGRtI^GV`uXLDt`GACv`slNSL`|JoJ$t*6eIMROPd$f#m z75>{9;lP(xWacc|#lGk(^%24W7KZXe~ZZaWO#9>X$pyCRT`k2K!5bC^E!~^lO|# zUvgQF!OXuNv*>+z*Ey=bz4YEoLIu_QsPvw{orwHX!@cOcidbEE~p@>vmQKW+AhZOQ@N~Fu5Msfv)Qje90*|sI55EIFE9h{i=6zuHQ~AUd!jLO6^9(* z+&y(iT2GVCV^H_#8G4XKl1MeK5KnenrV?nMXQ!l%d(T;8|R(En+fp z$#8<+>)D(&TRQkSLx%~LRtn>)FKqJpS(z^^AaSekAVOL5O?uPd$ye0KNrxk6OJarF zm77@_BvJq4>m-g71v6I|cW3Kt>L$0f+~`P~7UO62n4E7QIJmZvzaYGp`@ zLPFo%I&ojHKge@DdXV~VYWRx8E__0H>}XIHn&I?&sMH&&OS?hXoJz+?nOO%SJTlWF znGIu}gRoeUp4@j8YRH^mxkPPHy3pk{q%|@ z4J2nE!}m?*?zvtQb0X~=eR1+OeBrZ{ha}2hU$aQn+C@m$r!M0LF&g;7rF_HoCkrOq zC*PdMddDa!Jw;t6OEsKG;ZDKVyCZt1*f;Vwb~sN36W5=4Z6R=2wn=Fcf7WvX>9*#s zOkpKv{2=cW!?Kx_!Mr&6zN|sBkcl@Wn+8iSrODXr$tMU!w#Hjbc*P-DONv#U<&fXe zW7$petT6OV;*pxr__4~uyDo?N_N29(Lv{FN<+-h_u)OK;gke2uOIA7@SHi7(#Tmo6 zO6H;YS%1i%=q81_gcWvnId>yBI|a((tuO4rvcPr~2ozsK6IaxC#6{|a(6rHax zq_xP93uxK)T=fqn-QWigP4MFg^c%#7+jJU0;hEXrH)_;3Tr{X~FB>f#Eqyr}u%~Qv z>+Z4xr2%C}OGiiRP;Lp?&x6x5_q#n0CQGfbx~%Xz`LL8xs4VE%6PQ!EfsC72Qn@k_ zp?G8BRmTy$-m;R6HXrh8%SaIB?!yt-v6oT!cmq$irFR}jFxqTsN_Wt@jDp>@4ffgF zn-zNn1-q@|$u{zK#YqH724sYh?)zaI3}+}Mdw}9HDv3ax!{5zbuu@%E%sQ-X4l0{4UDC5#D0^Lf_dZ=ym6^L%e)&gyM{ZZ*z~B zUS(CLnq3E9d3C1Q0|wn8IRkDz;ESH)fFmeltAZ>LcBNb|wp}^+GJ5}zBk<)}Gz*-0 ziOmA>^Y2Wf_LWzp(k_FmC>pBasR}LVA7y3cf5XZ=ktn(saZm-)O3j z(Mq-RV8`_(as;_zdz>U!?17W)54Sdz?`7za6#+zjvSJ@`Ia%SYSVmT?BgLVV>m3g$ zlqiQItW{)+_2RNr-8%j30SgnTSF&8HCtLX!G8RR;1?Scl-lo03%@I5b-)bt4TpNQz zQZzl-+I{UD!9#LH)JARYn|wNP=O~U1uSoWnEDpkw6?@w+qezyZ2zk}AMZoH*GnGpt zfo7N1=G3(Qy`UnuJlUU6oS%z=>xDfV*wbBSYP|y#v&(D!CGlu*SxiTz8N}8ANSLbt zi7p_K?{0mUYSh*`6d%5MR5pGOGuQw$@*#}`Ai3i@P^JxW1vN&V>&e#a&Eg39_4UYW<2^mt z6@9;Q1XnB!(@x+HRO@9An1lr2B!#Z}WX3lMWvOu1k?es-A#OOrF4M}R%{$2_k~xAG z&W5J+lXv1!v}Jiu2lkmw?zA#4cWXOF(+hh#u(YS#l`4{{&YEWq|YB?o3VYjbUAomG@+tM)|Zhq-w_ju0xRat$+(m zqdJy`g)zutD}eNuKq+Q5pf?6eqfmgJ7PqEFfYQ5pv)Q5rP!Py~0>2he2u-X^N6Pcw zH@4ns330$l+O1ZSiRKQasnnW~>;Wzxcr%tS<_L5r8aRTciCT^zZ$i!yScW6P2t)4l zoiY}sG`77YBe5Op+2yHeRkyMS9HbOwd8+bGoF-Y}hJIxn{yn@eog-j}e`6~58I3`8 zP%S;!Vdang32$rZ?Y9eh>H=u6Sl~H5z>kQgz)Mtq90GaOPmotZE<6Q!9~wL;15`8Nc23WE*<{b7pNZAfva$l%{ekU7fvNn@sI=oQ`4>BJ3T}u*@W? z?;47gSmw!I?0rEr+*rF43QQZC5vJB(BaF!H+ak(S!>Wnd19Si|EIAu{oi+Mee+4xj z6<5iDoZZCKdMmdql~q@kJ+K&xd;5D#atDkXtF1|Ewr|UOpV_*KOq1_qRz-_9j`gKwi{DN0 z>72-s$Ax;Jd=rC3lYc{s9m^HJi{M2)>v*3m(t9>F(IG-GPrp!T%hH^XC4GLxS`5FX zFkz|(>(jDS{`;B`w+&t|zLK}sEJ@sE;@yX9YI;_y)x6CG`v^$x6FC#hOKaZJ62H&& zPE+KK@rF)Uz7h#dF;aiU@5=W*vTvAIYMa{YhQuC>n@$r#o0ikpsRLMWu=9j8lz0bO z&~cgS%l{r(J((gBDy*hVo{kjoLOX_7GBeLS@$X2fd^MR?+pesz*p9t)BC{qrJm)x$ z@W+<5Wc1g-DAiu#j2m6f+a8srIsW7xcz+>?6QP;I5t&sD&o}6Ju$#D-ID%`>Eli{K2Y_fn zvGinz^-?$j`g0I=egNwLQXgo`tPKUNp?nE?Nrrmq2V{>yL(v9`8F0`@?Q+mayPUvP zm63^N`^!^xYjd&(QgTi-R!f{M{7O@us^(`8Jk1Hh5#npwusOfK6cxwG-$~rM^KFvY<-H^$JNy+d%I>O9{#sZIv!DIJ5I%9_q z4X!OAIpyLCz>B1hsprnecVR0(eOESvbE|q|X7UNuXK&2*eNyr9E`T%YQgAK(Ki&lZ zp(NPgaE|W&-ZVA&|L`qYqnd3wkhE~7xgoyLi!vxdukQXOxq{pGAp+>)0}WMoRsGXR z_*nd*e_ntl3RKLbC7+t-u$n^`)Xq}@)j_TQlw$gFg1}ECFM{a2RJ&}I))~R7zXSiI zsYoqB?}H}jCFG}?X8PXxpXzb|R+vej^=gCKJP-uPbgxucKtDa$r!f#9bO;R@e?qL{|1>5;vxes$hqyn zX9nrRQ-y?$`p>`s{|>sROWhRnX`$f0i~lKn5#abdEdqluGZhx0AiVUC^TF_wx`nE` z!|s0GDjXb3b=4doO%ot5c>!Dw+rwyeDRje!rfn!rg;c%>JgD;kHsmwy_mihRzzCEs znDJlxtk#Vd5Sa?3{O8aRfb|0`=M7u{f|~Yq$2mf^MV~b8g9kw3d({8vy9CnKn8A z5M&6v>fc)*(2pa**FU6q>h!b$_uS0VP=P_&&(btDfv8nZdBPV5MNCzVDq`B=d;@u) zG0;Q@zvrlf`aF<>YW|{tj5>Yh@5!J7YX3#>0XBx{|9hCDV}QzWC;UhN=;k_r0Cy5x z*AoIi6zc2g_cK1wJ7hcDCIle8e_FI|I~=p;7aP<;`#p{`wTHdWoC*#04uL}f0HX>3 zTLS~IK={X02HH0hyA~b^@kaRuf-8qqi>d`M5mbc%p9On?Jp#ZE!|{K&ZI{$Kq2XTk zvo}r!PWM4KwC-%(>iVIhuG404o$09Szv*cD{pkV!3dqn@GuY2cJ~kaDp`}bcgC#TIc^0C({Rh1+CyvWM83LBaa;Y1Y;12XsYxfv+olIEj5E0;!jQU$yyWwh#?C? z5oe`(z%e$sKp%IEBR&*hHmZi}06xGw2~a{~0&Qs**aqVR1HpDeHIM&~FHrw6t$8>- zD>i^4Et>#ef7KOZ08h=+&pzw!{^`j9xi7S9S@+#{AS6OmDgu?eXaNB;=`+8zc`)rh z>c9={VC?Z=52C_qQ?2ZOhkEui`bjV(j;Q8_gFNthsQYSe07eFR@ZT|KHT4%kdWzJ{ z>M5hzrm7%CA>_VO?f}~IpCrtvpAC8i(U^b_P!FyAA8u5G5aa$)z)TYW!#|{xYKt3z z`i~Y@Z5Zvx9Sk9j)4R4^?jhc);%SqsvMQ7RgJ4jckn*u^u`NCz0IVCn_<)dSYMpwZ zdbX`2c_kWM$2nV3XQ$PjT910N&Rc?IP*WcTI#@XzT z)83qeRv3>@=$3x)x4)+a(); AmplifyBloomEffect component2 = GetComponent(); UltimateBloom component3 = GetComponent(); - SSREffect component4 = GetComponent(); + //SSREffect component4 = GetComponent(); PKFxRenderingPlugin component5 = GetComponent(); SunShafts component6 = GetComponent(); SEGI component7 = GetComponent(); - VolumetricFog component8 = GetComponent(); + //VolumetricFog component8 = GetComponent(); FieCommandBufferReflection component9 = GetComponent(); switch (qualityLevel) { @@ -78,10 +78,10 @@ namespace Fie.Camera { component3.enabled = false; } - if (component4 != null) - { - component4.enabled = false; - } + // if (component4 != null) + // { + // component4.enabled = false; + // } if (component5 != null) { component5.m_EnableDistortion = false; @@ -98,10 +98,10 @@ namespace Fie.Camera { component7.enabled = false; } - if (component8 != null) - { - component8.enabled = false; - } + // if (component8 != null) + // { + // component8.enabled = false; + // } if (component9 != null) { component9.enabled = false; @@ -117,10 +117,10 @@ namespace Fie.Camera { component3.enabled = false; } - if (component4 != null) - { - component4.enabled = false; - } + // if (component4 != null) + // { + // component4.enabled = false; + // } if (component5 != null) { component5.m_EnableDistortion = false; @@ -137,10 +137,10 @@ namespace Fie.Camera { component7.enabled = false; } - if (component8 != null) - { - component8.enabled = false; - } + // if (component8 != null) + // { + // component8.enabled = false; + // } if (component9 != null) { component9.enabled = false; @@ -160,10 +160,10 @@ namespace Fie.Camera { component3.enabled = true; } - if (component4 != null) - { - component4.enabled = false; - } + // if (component4 != null) + // { + // component4.enabled = false; + // } if (component5 != null) { component5.m_EnableDistortion = true; @@ -184,10 +184,10 @@ namespace Fie.Camera { component.profile = PostProcessingProfileForLev3; } - if (component8 != null) - { - component8.enabled = false; - } + // if (component8 != null) + // { + // component8.enabled = false; + // } if (component9 != null) { component9.enabled = true; @@ -207,10 +207,10 @@ namespace Fie.Camera { component3.enabled = true; } - if (component4 != null) - { - component4.enabled = true; - } + // if (component4 != null) + // { + // component4.enabled = true; + // } if (component5 != null) { component5.m_EnableDistortion = true; @@ -231,10 +231,10 @@ namespace Fie.Camera { component.profile = PostProcessingProfileForLev4; } - if (component8 != null) - { - component8.enabled = true; - } + // if (component8 != null) + // { + // component8.enabled = true; + // } if (component9 != null) { component9.enabled = true; @@ -254,10 +254,10 @@ namespace Fie.Camera { component3.enabled = true; } - if (component4 != null) - { - component4.enabled = true; - } + // if (component4 != null) + // { + // component4.enabled = true; + // } if (component5 != null) { component5.m_EnableDistortion = true; @@ -278,10 +278,10 @@ namespace Fie.Camera { component.profile = PostProcessingProfileForLev5; } - if (component8 != null) - { - component8.enabled = true; - } + // if (component8 != null) + // { + // component8.enabled = true; + // } if (component9 != null) { component9.enabled = true; diff --git a/Assets/Scripts/Fie/Title/FieTitleAuthController.cs b/Assets/Scripts/Fie/Title/FieTitleAuthController.cs index e49603f..57cafd9 100644 --- a/Assets/Scripts/Fie/Title/FieTitleAuthController.cs +++ b/Assets/Scripts/Fie/Title/FieTitleAuthController.cs @@ -1,5 +1,5 @@ using Fie.Manager; -using MBS; +//using MBS; using UnityEngine; namespace Fie.Title @@ -15,8 +15,8 @@ namespace Fie.Title UNNECESSARY } - [SerializeField] - private WUUGLoginGUI _loginGUIComponent; + //[SerializeField] + //private WUUGLoginGUI _loginGUIComponent; public event FinishedLoginProcessCallback finishedEvent; @@ -26,14 +26,14 @@ namespace Fie.Title { return RecomendedLoginState.UNNECESSARY; } - if (WULogin.logged_in) - { - if (!PhotonNetwork.connected) - { - return RecomendedLoginState.CONNECT_TO_MASTER; - } - return RecomendedLoginState.UNNECESSARY; - } + // if (WULogin.logged_in) + // { + // if (!PhotonNetwork.connected) + // { + // return RecomendedLoginState.CONNECT_TO_MASTER; + // } + // return RecomendedLoginState.UNNECESSARY; + // } return RecomendedLoginState.AUTH; } @@ -42,9 +42,9 @@ namespace Fie.Title switch (recomendedState) { case RecomendedLoginState.AUTH: - _loginGUIComponent.gameObject.SetActive(value: true); - _loginGUIComponent.InitWULoginGUI(); - _loginGUIComponent.loginEvent += _loginGUIComponent_loginCallback; + // _loginGUIComponent.gameObject.SetActive(value: true); + // _loginGUIComponent.InitWULoginGUI(); + // _loginGUIComponent.loginEvent += _loginGUIComponent_loginCallback; break; case RecomendedLoginState.CONNECT_TO_MASTER: FieManagerBehaviour.I.connectedToMasterServerEvent += _connectedToMasterServerCallback; diff --git a/fie.csproj b/fie.csproj index 37f5c90..3af0ebf 100644 --- a/fie.csproj +++ b/fie.csproj @@ -2316,6 +2316,60 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

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